10
10
11
11
use borrow_check:: nll:: constraints:: { OutlivesConstraint } ;
12
12
use borrow_check:: nll:: region_infer:: RegionInferenceContext ;
13
+ use borrow_check:: nll:: region_infer:: error_reporting:: region_name:: RegionNameSource ;
13
14
use borrow_check:: nll:: type_check:: Locations ;
15
+ use borrow_check:: nll:: universal_regions:: DefiningTy ;
14
16
use rustc:: hir:: def_id:: DefId ;
15
17
use rustc:: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
16
18
use rustc:: infer:: InferCtxt ;
@@ -263,6 +265,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
263
265
debug ! ( "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}" ,
264
266
fr_is_local, outlived_fr_is_local, category) ;
265
267
match ( category, fr_is_local, outlived_fr_is_local) {
268
+ ( ConstraintCategory :: Return , true , false ) if self . is_closure_fn_mut ( infcx, fr) =>
269
+ self . report_fnmut_error ( mir, infcx, mir_def_id, fr, outlived_fr, span,
270
+ errors_buffer) ,
266
271
( ConstraintCategory :: Assignment , true , false ) |
267
272
( ConstraintCategory :: CallArgument , true , false ) =>
268
273
self . report_escaping_data_error ( mir, infcx, mir_def_id, fr, outlived_fr,
@@ -274,6 +279,75 @@ impl<'tcx> RegionInferenceContext<'tcx> {
274
279
} ;
275
280
}
276
281
282
+ /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
283
+ /// This function expects `fr` to be local and `outlived_fr` to not be local.
284
+ ///
285
+ /// ```text
286
+ /// error: captured variable cannot escape `FnMut` closure body
287
+ /// --> $DIR/issue-53040.rs:15:8
288
+ /// |
289
+ /// LL | || &mut v;
290
+ /// | -- ^^^^^^ creates a reference to a captured variable which escapes the closure body
291
+ /// | |
292
+ /// | inferred to be a `FnMut` closure
293
+ /// |
294
+ /// = note: `FnMut` closures only have access to their captured variables while they are
295
+ /// executing...
296
+ /// = note: ...therefore, returned references to captured variables will escape the closure
297
+ /// ```
298
+ fn report_fnmut_error (
299
+ & self ,
300
+ mir : & Mir < ' tcx > ,
301
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
302
+ mir_def_id : DefId ,
303
+ _fr : RegionVid ,
304
+ outlived_fr : RegionVid ,
305
+ span : Span ,
306
+ errors_buffer : & mut Vec < Diagnostic > ,
307
+ ) {
308
+ let mut diag = infcx. tcx . sess . struct_span_err (
309
+ span,
310
+ "captured variable cannot escape `FnMut` closure body" ,
311
+ ) ;
312
+
313
+ diag. span_label (
314
+ span,
315
+ "creates a reference to a captured variable which escapes the closure body" ,
316
+ ) ;
317
+
318
+ match self . give_region_a_name ( infcx, mir, mir_def_id, outlived_fr, & mut 1 ) . source {
319
+ RegionNameSource :: NamedEarlyBoundRegion ( fr_span) |
320
+ RegionNameSource :: NamedFreeRegion ( fr_span) |
321
+ RegionNameSource :: SynthesizedFreeEnvRegion ( fr_span, _) |
322
+ RegionNameSource :: CannotMatchHirTy ( fr_span, _) |
323
+ RegionNameSource :: MatchedHirTy ( fr_span) |
324
+ RegionNameSource :: MatchedAdtAndSegment ( fr_span) |
325
+ RegionNameSource :: AnonRegionFromUpvar ( fr_span, _) |
326
+ RegionNameSource :: AnonRegionFromOutput ( fr_span, _, _) => {
327
+ diag. span_label ( fr_span, "inferred to be a `FnMut` closure" ) ;
328
+ } ,
329
+ _ => { } ,
330
+ }
331
+
332
+ diag. note ( "`FnMut` closures only have access to their captured variables while they are \
333
+ executing...") ;
334
+ diag. note ( "...therefore, they cannot allow references to captured variables to escape" ) ;
335
+
336
+ diag. buffer ( errors_buffer) ;
337
+ }
338
+
339
+ /// Reports a error specifically for when data is escaping a closure.
340
+ ///
341
+ /// ```text
342
+ /// error: borrowed data escapes outside of function
343
+ /// --> $DIR/lifetime-bound-will-change-warning.rs:44:5
344
+ /// |
345
+ /// LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
346
+ /// | - `x` is a reference that is only valid in the function body
347
+ /// LL | // but ref_obj will not, so warn.
348
+ /// LL | ref_obj(x)
349
+ /// | ^^^^^^^^^^ `x` escapes the function body here
350
+ /// ```
277
351
fn report_escaping_data_error (
278
352
& self ,
279
353
mir : & Mir < ' tcx > ,
@@ -305,31 +379,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
305
379
span, & format ! ( "borrowed data escapes outside of {}" , escapes_from) ,
306
380
) ;
307
381
308
- if let Some ( ( outlived_fr_name, outlived_fr_span) ) = outlived_fr_name_and_span {
309
- if let Some ( name) = outlived_fr_name {
310
- diag. span_label (
311
- outlived_fr_span,
312
- format ! ( "`{}` is declared here, outside of the {} body" , name, escapes_from) ,
313
- ) ;
314
- }
382
+ if let Some ( ( Some ( outlived_fr_name) , outlived_fr_span) ) = outlived_fr_name_and_span {
383
+ diag. span_label (
384
+ outlived_fr_span,
385
+ format ! (
386
+ "`{}` is declared here, outside of the {} body" ,
387
+ outlived_fr_name, escapes_from
388
+ ) ,
389
+ ) ;
315
390
}
316
391
317
- if let Some ( ( fr_name, fr_span) ) = fr_name_and_span {
318
- if let Some ( name) = fr_name {
319
- diag. span_label (
320
- fr_span,
321
- format ! ( "`{}` is a reference that is only valid in the {} body" ,
322
- name, escapes_from) ,
323
- ) ;
392
+ if let Some ( ( Some ( fr_name) , fr_span) ) = fr_name_and_span {
393
+ diag. span_label (
394
+ fr_span,
395
+ format ! (
396
+ "`{}` is a reference that is only valid in the {} body" ,
397
+ fr_name, escapes_from
398
+ ) ,
399
+ ) ;
324
400
325
- diag. span_label ( span, format ! ( "`{}` escapes the {} body here" ,
326
- name, escapes_from) ) ;
327
- }
401
+ diag. span_label ( span, format ! ( "`{}` escapes the {} body here" , fr_name, escapes_from) ) ;
328
402
}
329
403
330
404
diag. buffer ( errors_buffer) ;
331
405
}
332
406
407
+ /// Reports a region inference error for the general case with named/synthesized lifetimes to
408
+ /// explain what is happening.
409
+ ///
410
+ /// ```text
411
+ /// error: unsatisfied lifetime constraints
412
+ /// --> $DIR/regions-creating-enums3.rs:17:5
413
+ /// |
414
+ /// LL | fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
415
+ /// | -- -- lifetime `'b` defined here
416
+ /// | |
417
+ /// | lifetime `'a` defined here
418
+ /// LL | ast::add(x, y)
419
+ /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
420
+ /// | is returning data with lifetime `'b`
421
+ /// ```
333
422
fn report_general_error (
334
423
& self ,
335
424
mir : & Mir < ' tcx > ,
@@ -380,6 +469,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
380
469
diag. buffer ( errors_buffer) ;
381
470
}
382
471
472
+ /// Adds a suggestion to errors where a `impl Trait` is returned.
473
+ ///
474
+ /// ```text
475
+ /// help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as
476
+ /// a constraint
477
+ /// |
478
+ /// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
479
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
480
+ /// ```
383
481
fn add_static_impl_trait_suggestion (
384
482
& self ,
385
483
infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
@@ -500,4 +598,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
500
598
. get ( & ( constraint. sup , constraint. sub ) ) ;
501
599
* opt_span_category. unwrap_or ( & ( constraint. category , mir. source_info ( loc) . span ) )
502
600
}
601
+
602
+ /// Returns `true` if a closure is inferred to be an `FnMut` closure.
603
+ crate fn is_closure_fn_mut (
604
+ & self ,
605
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
606
+ fr : RegionVid ,
607
+ ) -> bool {
608
+ if let Some ( ty:: ReFree ( free_region) ) = self . to_error_region ( fr) {
609
+ if let ty:: BoundRegion :: BrEnv = free_region. bound_region {
610
+ if let DefiningTy :: Closure ( def_id, substs) = self . universal_regions . defining_ty {
611
+ let closure_kind_ty = substs. closure_kind_ty ( def_id, infcx. tcx ) ;
612
+ return Some ( ty:: ClosureKind :: FnMut ) == closure_kind_ty. to_opt_closure_kind ( ) ;
613
+ }
614
+ }
615
+ }
616
+
617
+ false
618
+ }
503
619
}
0 commit comments