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