@@ -123,7 +123,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
123
123
Origin :: Mir ,
124
124
) ;
125
125
126
- self . add_closure_invoked_twice_with_moved_variable_suggestion (
126
+ self . add_moved_or_invoked_closure_note (
127
127
context. loc ,
128
128
used_place,
129
129
& mut err,
@@ -1331,7 +1331,8 @@ enum StorageDeadOrDrop<'tcx> {
1331
1331
1332
1332
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
1333
1333
1334
- /// Adds a suggestion when a closure is invoked twice with a moved variable.
1334
+ /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
1335
+ /// is moved after being invoked.
1335
1336
///
1336
1337
/// ```text
1337
1338
/// note: closure cannot be invoked more than once because it moves the variable `dict` out of
@@ -1341,30 +1342,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1341
1342
/// LL | for (key, value) in dict {
1342
1343
/// | ^^^^
1343
1344
/// ```
1344
- pub ( super ) fn add_closure_invoked_twice_with_moved_variable_suggestion (
1345
+ pub ( super ) fn add_moved_or_invoked_closure_note (
1345
1346
& self ,
1346
1347
location : Location ,
1347
1348
place : & Place < ' tcx > ,
1348
1349
diag : & mut DiagnosticBuilder < ' _ > ,
1349
1350
) {
1351
+ debug ! ( "add_moved_or_invoked_closure_note: location={:?} place={:?}" , location, place) ;
1350
1352
let mut target = place. local ( ) ;
1351
- debug ! (
1352
- "add_closure_invoked_twice_with_moved_variable_suggestion: location={:?} place={:?} \
1353
- target={:?}",
1354
- location, place, target,
1355
- ) ;
1356
1353
for stmt in & self . mir [ location. block ] . statements [ location. statement_index ..] {
1357
- debug ! (
1358
- "add_closure_invoked_twice_with_moved_variable_suggestion: stmt={:?} \
1359
- target={:?}",
1360
- stmt, target,
1361
- ) ;
1354
+ debug ! ( "add_moved_or_invoked_closure_note: stmt={:?} target={:?}" , stmt, target) ;
1362
1355
if let StatementKind :: Assign ( into, box Rvalue :: Use ( from) ) = & stmt. kind {
1363
- debug ! (
1364
- "add_closure_invoked_twice_with_moved_variable_suggestion: into={:?} \
1365
- from={:?}",
1366
- into, from,
1367
- ) ;
1356
+ debug ! ( "add_fnonce_closure_note: into={:?} from={:?}" , into, from) ;
1368
1357
match from {
1369
1358
Operand :: Copy ( ref place) |
1370
1359
Operand :: Move ( ref place) if target == place. local ( ) =>
@@ -1374,12 +1363,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1374
1363
}
1375
1364
}
1376
1365
1377
-
1366
+ // Check if we are attempting to call a closure after it has been invoked.
1378
1367
let terminator = self . mir [ location. block ] . terminator ( ) ;
1379
- debug ! (
1380
- "add_closure_invoked_twice_with_moved_variable_suggestion: terminator={:?}" ,
1381
- terminator,
1382
- ) ;
1368
+ debug ! ( "add_moved_or_invoked_closure_note: terminator={:?}" , terminator) ;
1383
1369
if let TerminatorKind :: Call {
1384
1370
func : Operand :: Constant ( box Constant {
1385
1371
literal : ty:: Const { ty : & ty:: TyS { sty : ty:: TyKind :: FnDef ( id, _) , .. } , .. } ,
@@ -1388,41 +1374,59 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1388
1374
args,
1389
1375
..
1390
1376
} = & terminator. kind {
1391
- debug ! ( "add_closure_invoked_twice_with_moved_variable_suggestion : id={:?}" , id) ;
1377
+ debug ! ( "add_moved_or_invoked_closure_note : id={:?}" , id) ;
1392
1378
if self . infcx . tcx . parent ( id) == self . infcx . tcx . lang_items ( ) . fn_once_trait ( ) {
1393
1379
let closure = match args. first ( ) {
1394
1380
Some ( Operand :: Copy ( ref place) ) |
1395
1381
Some ( Operand :: Move ( ref place) ) if target == place. local ( ) =>
1396
1382
place. local ( ) . unwrap ( ) ,
1397
1383
_ => return ,
1398
1384
} ;
1399
- debug ! (
1400
- "add_closure_invoked_twice_with_moved_variable_suggestion: closure={:?}" ,
1401
- closure,
1402
- ) ;
1403
1385
1404
- if let ty:: TyKind :: Closure ( did, _substs) = self . mir . local_decls [ closure] . ty . sty {
1405
- let node_id = match self . infcx . tcx . hir ( ) . as_local_node_id ( did) {
1406
- Some ( node_id) => node_id,
1407
- _ => return ,
1408
- } ;
1386
+ debug ! ( "add_moved_or_invoked_closure_note: closure={:?}" , closure) ;
1387
+ if let ty:: TyKind :: Closure ( did, _) = self . mir . local_decls [ closure] . ty . sty {
1388
+ let node_id = self . infcx . tcx . hir ( ) . as_local_node_id ( did) . unwrap ( ) ;
1409
1389
let hir_id = self . infcx . tcx . hir ( ) . node_to_hir_id ( node_id) ;
1410
1390
1411
- if let Some ( (
1412
- span, name
1413
- ) ) = self . infcx . tcx . typeck_tables_of ( did) . closure_kind_origins ( ) . get ( hir_id) {
1391
+ if let Some ( ( span, name) ) = self . infcx . tcx . typeck_tables_of ( did)
1392
+ . closure_kind_origins ( )
1393
+ . get ( hir_id)
1394
+ {
1414
1395
diag. span_note (
1415
1396
* span,
1416
1397
& format ! (
1417
- "closure cannot be invoked more than once because it \
1418
- moves the variable `{}` out of its environment",
1419
- name,
1398
+ "closure cannot be invoked more than once because it moves the \
1399
+ variable `{}` out of its environment",
1400
+ name,
1420
1401
) ,
1421
1402
) ;
1403
+ return ;
1422
1404
}
1423
1405
}
1424
1406
}
1425
1407
}
1408
+
1409
+ // Check if we are just moving a closure after it has been invoked.
1410
+ if let Some ( target) = target {
1411
+ if let ty:: TyKind :: Closure ( did, _) = self . mir . local_decls [ target] . ty . sty {
1412
+ let node_id = self . infcx . tcx . hir ( ) . as_local_node_id ( did) . unwrap ( ) ;
1413
+ let hir_id = self . infcx . tcx . hir ( ) . node_to_hir_id ( node_id) ;
1414
+
1415
+ if let Some ( ( span, name) ) = self . infcx . tcx . typeck_tables_of ( did)
1416
+ . closure_kind_origins ( )
1417
+ . get ( hir_id)
1418
+ {
1419
+ diag. span_note (
1420
+ * span,
1421
+ & format ! (
1422
+ "closure cannot be moved more than once as it is not `Copy` due to \
1423
+ moving the variable `{}` out of its environment",
1424
+ name
1425
+ ) ,
1426
+ ) ;
1427
+ }
1428
+ }
1429
+ }
1426
1430
}
1427
1431
1428
1432
/// End-user visible description of `place` if one can be found. If the
0 commit comments