@@ -13,9 +13,9 @@ use borrow_check::prefixes::IsPrefixOf;
13
13
use borrow_check:: nll:: explain_borrow:: BorrowExplanation ;
14
14
use rustc:: middle:: region:: ScopeTree ;
15
15
use rustc:: mir:: {
16
- AggregateKind , BindingForm , BorrowKind , ClearCrossCrate , FakeReadCause , Field , Local ,
16
+ self , AggregateKind , BindingForm , BorrowKind , ClearCrossCrate , FakeReadCause , Field , Local ,
17
17
LocalDecl , LocalKind , Location , Operand , Place , ProjectionElem , Rvalue , Statement ,
18
- StatementKind , VarBindingForm ,
18
+ StatementKind , TerminatorKind , VarBindingForm ,
19
19
} ;
20
20
use rustc:: hir;
21
21
use rustc:: hir:: def_id:: DefId ;
@@ -518,14 +518,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
518
518
519
519
err. span_label (
520
520
borrow_span,
521
- format ! ( "`{}` would have to be valid for `{}`" , name, region_name)
521
+ format ! ( "`{}` would have to be valid for `{}`... " , name, region_name)
522
522
) ;
523
523
524
524
if let Some ( fn_node_id) = self . infcx . tcx . hir . as_local_node_id ( self . mir_def_id ) {
525
525
err. span_label (
526
526
drop_span,
527
527
format ! (
528
- "but `{}` will be dropped here, when the function `{}` returns" ,
528
+ "... but `{}` will be dropped here, when the function `{}` returns" ,
529
529
name, self . infcx. tcx. hir. name( fn_node_id) ,
530
530
)
531
531
) ;
@@ -1173,54 +1173,211 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1173
1173
& self ,
1174
1174
borrow : & BorrowData < ' tcx > ,
1175
1175
) -> Option < AnnotatedBorrowFnSignature > {
1176
- // There are two cases that need handled: when a closure is involved and
1177
- // when a closure is not involved.
1178
- let location = borrow. reserve_location ;
1179
- let is_closure = self . infcx . tcx . is_closure ( self . mir_def_id ) ;
1176
+ // Define a fallback for when we can't match a closure.
1177
+ let fallback = || {
1178
+ let is_closure = self . infcx . tcx . is_closure ( self . mir_def_id ) ;
1179
+ if is_closure {
1180
+ None
1181
+ } else {
1182
+ let ty = self . infcx . tcx . type_of ( self . mir_def_id ) ;
1183
+ match ty. sty {
1184
+ ty:: TyKind :: FnDef ( _, _) | ty:: TyKind :: FnPtr ( _) =>
1185
+ self . annotate_fn_sig (
1186
+ self . mir_def_id ,
1187
+ self . infcx . tcx . fn_sig ( self . mir_def_id )
1188
+ ) ,
1189
+ _ => None ,
1190
+ }
1191
+ }
1192
+ } ;
1180
1193
1181
- match self . mir [ location. block ] . statements . get ( location. statement_index ) {
1182
- // When a closure is involved, we expect the reserve location to be an assignment
1183
- // to a temporary local, which will be followed by a closure.
1194
+ // In order to determine whether we need to annotate, we need to check whether the reserve
1195
+ // place was an assignment into a temporary.
1196
+ //
1197
+ // If it was, we check whether or not that temporary is eventually assigned into the return
1198
+ // place. If it was, we can add annotations about the function's return type and arguments
1199
+ // and it'll make sense.
1200
+ let location = borrow. reserve_location ;
1201
+ debug ! ( "annotate_argument_and_return_for_borrow: location={:?}" , location) ;
1202
+ match & self . mir [ location. block ] . statements . get ( location. statement_index ) {
1184
1203
Some ( & Statement {
1185
- kind : StatementKind :: Assign ( Place :: Local ( local ) , _) ,
1204
+ kind : StatementKind :: Assign ( ref reservation , _) ,
1186
1205
..
1187
- } ) if self . mir . local_kind ( local) == LocalKind :: Temp => {
1188
- // Look for the statements within this block after assigning to a local to see
1189
- // if we have a closure. If we do, then annotate it.
1206
+ } ) => {
1207
+ debug ! ( "annotate_argument_and_return_for_borrow: reservation={:?}" , reservation) ;
1208
+ // Check that the initial assignment of the reserve location is into a temporary.
1209
+ let mut target = * match reservation {
1210
+ Place :: Local ( local) if self . mir . local_kind ( * local) == LocalKind :: Temp => local,
1211
+ _ => return None ,
1212
+ } ;
1213
+
1214
+ // Next, look through the rest of the block, checking if we are assigning the
1215
+ // `target` (that is, the place that contains our borrow) to anything.
1216
+ let mut annotated_closure = None ;
1190
1217
for stmt in & self . mir [ location. block ] . statements [ location. statement_index + 1 ..] {
1218
+ debug ! (
1219
+ "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}" ,
1220
+ target, stmt
1221
+ ) ;
1191
1222
if let StatementKind :: Assign (
1192
- _,
1193
- Rvalue :: Aggregate (
1194
- box AggregateKind :: Closure ( def_id, substs) ,
1195
- _
1196
- )
1197
- ) = stmt. kind {
1198
- return self . annotate_fn_sig (
1199
- def_id,
1200
- self . infcx . closure_sig ( def_id, substs)
1223
+ Place :: Local ( assigned_to) ,
1224
+ rvalue,
1225
+ ) = & stmt. kind {
1226
+ debug ! ( "annotate_argument_and_return_for_borrow: assigned_to={:?} \
1227
+ rvalue={:?}", assigned_to, rvalue) ;
1228
+ // Check if our `target` was captured by a closure.
1229
+ if let Rvalue :: Aggregate (
1230
+ box AggregateKind :: Closure ( def_id, substs) ,
1231
+ operands,
1232
+ ) = rvalue {
1233
+ for operand in operands {
1234
+ let assigned_from = match operand {
1235
+ Operand :: Copy ( assigned_from) |
1236
+ Operand :: Move ( assigned_from) => assigned_from,
1237
+ _ => continue ,
1238
+ } ;
1239
+ debug ! (
1240
+ "annotate_argument_and_return_for_borrow: assigned_from={:?}" ,
1241
+ assigned_from
1242
+ ) ;
1243
+
1244
+ // Find the local from the operand.
1245
+ let assigned_from_local = match assigned_from. local ( ) {
1246
+ Some ( local) => local,
1247
+ None => continue ,
1248
+ } ;
1249
+
1250
+ if assigned_from_local != target {
1251
+ continue ;
1252
+ }
1253
+
1254
+ // If a closure captured our `target` and then assigned
1255
+ // into a place then we should annotate the closure in
1256
+ // case it ends up being assigned into the return place.
1257
+ annotated_closure = self . annotate_fn_sig (
1258
+ * def_id,
1259
+ self . infcx . closure_sig ( * def_id, * substs)
1260
+ ) ;
1261
+ debug ! (
1262
+ "annotate_argument_and_return_for_borrow: \
1263
+ annotated_closure={:?} assigned_from_local={:?} \
1264
+ assigned_to={:?}",
1265
+ annotated_closure, assigned_from_local, assigned_to
1266
+ ) ;
1267
+
1268
+ if * assigned_to == mir:: RETURN_PLACE {
1269
+ // If it was assigned directly into the return place, then
1270
+ // return now.
1271
+ return annotated_closure;
1272
+ } else {
1273
+ // Otherwise, update the target.
1274
+ target = * assigned_to;
1275
+ }
1276
+ }
1277
+
1278
+ // If none of our closure's operands matched, then skip to the next
1279
+ // statement.
1280
+ continue ;
1281
+ }
1282
+
1283
+ // Otherwise, look at other types of assignment.
1284
+ let assigned_from = match rvalue {
1285
+ Rvalue :: Ref ( _, _, assigned_from) => assigned_from,
1286
+ Rvalue :: Use ( operand) => match operand {
1287
+ Operand :: Copy ( assigned_from) |
1288
+ Operand :: Move ( assigned_from) => assigned_from,
1289
+ _ => continue ,
1290
+ } ,
1291
+ _ => continue ,
1292
+ } ;
1293
+ debug ! (
1294
+ "annotate_argument_and_return_for_borrow: \
1295
+ assigned_from={:?}", assigned_from,
1296
+ ) ;
1297
+
1298
+ // Find the local from the rvalue.
1299
+ let assigned_from_local = match assigned_from. local ( ) {
1300
+ Some ( local) => local,
1301
+ None => continue ,
1302
+ } ;
1303
+ debug ! (
1304
+ "annotate_argument_and_return_for_borrow: \
1305
+ assigned_from_local={:?}", assigned_from_local,
1201
1306
) ;
1307
+
1308
+ // Check if our local matches the target - if so, we've assigned our
1309
+ // borrow to a new place.
1310
+ if assigned_from_local != target {
1311
+ continue ;
1312
+ }
1313
+
1314
+ // If we assigned our `target` into a new place, then we should
1315
+ // check if it was the return place.
1316
+ debug ! (
1317
+ "annotate_argument_and_return_for_borrow: \
1318
+ assigned_from_local={:?} assigned_to={:?}",
1319
+ assigned_from_local, assigned_to
1320
+ ) ;
1321
+ if * assigned_to == mir:: RETURN_PLACE {
1322
+ // If it was then return the annotated closure if there was one,
1323
+ // else, annotate this function.
1324
+ return annotated_closure. or_else ( fallback) ;
1325
+ }
1326
+
1327
+ // If we didn't assign into the return place, then we just update
1328
+ // the target.
1329
+ target = * assigned_to;
1330
+ }
1331
+ }
1332
+
1333
+ // Check the terminator if we didn't find anything in the statements.
1334
+ let terminator = & self . mir [ location. block ] . terminator ( ) ;
1335
+ debug ! (
1336
+ "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}" ,
1337
+ target, terminator
1338
+ ) ;
1339
+ if let TerminatorKind :: Call {
1340
+ destination : Some ( ( Place :: Local ( assigned_to) , _) ) ,
1341
+ args,
1342
+ ..
1343
+ } = & terminator. kind {
1344
+ debug ! (
1345
+ "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}" ,
1346
+ assigned_to, args
1347
+ ) ;
1348
+ for operand in args {
1349
+ let assigned_from = match operand {
1350
+ Operand :: Copy ( assigned_from) |
1351
+ Operand :: Move ( assigned_from) => assigned_from,
1352
+ _ => continue ,
1353
+ } ;
1354
+ debug ! (
1355
+ "annotate_argument_and_return_for_borrow: assigned_from={:?}" ,
1356
+ assigned_from,
1357
+ ) ;
1358
+
1359
+ if let Some ( assigned_from_local) = assigned_from. local ( ) {
1360
+ debug ! (
1361
+ "annotate_argument_and_return_for_borrow: assigned_from_local={:?}" ,
1362
+ assigned_from_local,
1363
+ ) ;
1364
+
1365
+ if * assigned_to == mir:: RETURN_PLACE &&
1366
+ assigned_from_local == target
1367
+ {
1368
+ return annotated_closure. or_else ( fallback) ;
1369
+ }
1370
+ }
1202
1371
}
1203
1372
}
1204
1373
}
1205
1374
_ => { }
1206
1375
}
1207
1376
1208
- // If this is not the case, then return if we're currently on a closure (as we
1209
- // don't have a substs to get the PolyFnSig) or attempt to get the arguments
1210
- // and return type of the function.
1211
- if is_closure {
1212
- None
1213
- } else {
1214
- let ty = self . infcx . tcx . type_of ( self . mir_def_id ) ;
1215
- match ty. sty {
1216
- ty:: TyKind :: FnDef ( _, _) | ty:: TyKind :: FnPtr ( _) =>
1217
- self . annotate_fn_sig (
1218
- self . mir_def_id ,
1219
- self . infcx . tcx . fn_sig ( self . mir_def_id )
1220
- ) ,
1221
- _ => None ,
1222
- }
1223
- }
1377
+ // If we haven't found an assignment into the return place, then we need not add
1378
+ // any annotations.
1379
+ debug ! ( "annotate_argument_and_return_for_borrow: none found" ) ;
1380
+ None
1224
1381
}
1225
1382
1226
1383
/// Annotate the first argument and return type of a function signature if they are
@@ -1230,6 +1387,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1230
1387
did : DefId ,
1231
1388
sig : ty:: PolyFnSig < ' tcx > ,
1232
1389
) -> Option < AnnotatedBorrowFnSignature > {
1390
+ debug ! ( "annotate_fn_sig: did={:?} sig={:?}" , did, sig) ;
1233
1391
let is_closure = self . infcx . tcx . is_closure ( did) ;
1234
1392
let fn_node_id = self . infcx . tcx . hir . as_local_node_id ( did) ?;
1235
1393
let fn_decl = self . infcx . tcx . hir . fn_decl ( fn_node_id) ?;
0 commit comments