@@ -13,9 +13,9 @@ use borrow_check::prefixes::IsPrefixOf;
1313use borrow_check:: nll:: explain_borrow:: BorrowExplanation ;
1414use rustc:: middle:: region:: ScopeTree ;
1515use rustc:: mir:: {
16- AggregateKind , BindingForm , BorrowKind , ClearCrossCrate , FakeReadCause , Field , Local ,
16+ self , AggregateKind , BindingForm , BorrowKind , ClearCrossCrate , FakeReadCause , Field , Local ,
1717 LocalDecl , LocalKind , Location , Operand , Place , ProjectionElem , Rvalue , Statement ,
18- StatementKind , VarBindingForm ,
18+ StatementKind , TerminatorKind , VarBindingForm ,
1919} ;
2020use rustc:: hir;
2121use rustc:: hir:: def_id:: DefId ;
@@ -518,14 +518,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
518518
519519 err. span_label (
520520 borrow_span,
521- format ! ( "`{}` would have to be valid for `{}`" , name, region_name)
521+ format ! ( "`{}` would have to be valid for `{}`... " , name, region_name)
522522 ) ;
523523
524524 if let Some ( fn_node_id) = self . infcx . tcx . hir . as_local_node_id ( self . mir_def_id ) {
525525 err. span_label (
526526 drop_span,
527527 format ! (
528- "but `{}` will be dropped here, when the function `{}` returns" ,
528+ "... but `{}` will be dropped here, when the function `{}` returns" ,
529529 name, self . infcx. tcx. hir. name( fn_node_id) ,
530530 )
531531 ) ;
@@ -1173,54 +1173,211 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11731173 & self ,
11741174 borrow : & BorrowData < ' tcx > ,
11751175 ) -> 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+ } ;
11801193
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 ) {
11841203 Some ( & Statement {
1185- kind : StatementKind :: Assign ( Place :: Local ( local ) , _) ,
1204+ kind : StatementKind :: Assign ( ref reservation , _) ,
11861205 ..
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 ;
11901217 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+ ) ;
11911222 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,
12011306 ) ;
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+ }
12021371 }
12031372 }
12041373 }
12051374 _ => { }
12061375 }
12071376
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
12241381 }
12251382
12261383 /// 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> {
12301387 did : DefId ,
12311388 sig : ty:: PolyFnSig < ' tcx > ,
12321389 ) -> Option < AnnotatedBorrowFnSignature > {
1390+ debug ! ( "annotate_fn_sig: did={:?} sig={:?}" , did, sig) ;
12331391 let is_closure = self . infcx . tcx . is_closure ( did) ;
12341392 let fn_node_id = self . infcx . tcx . hir . as_local_node_id ( did) ?;
12351393 let fn_decl = self . infcx . tcx . hir . fn_decl ( fn_node_id) ?;
0 commit comments