@@ -7,7 +7,7 @@ use rustc_errors::{
77} ;
88use rustc_hir as hir;
99use rustc_hir:: def_id:: DefId ;
10- use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
10+ use rustc_hir:: intravisit:: { walk_block , walk_expr, Visitor } ;
1111use rustc_hir:: { AsyncGeneratorKind , GeneratorKind } ;
1212use rustc_infer:: infer:: TyCtxtInferExt ;
1313use rustc_infer:: traits:: ObligationCause ;
@@ -23,7 +23,7 @@ use rustc_middle::ty::{
2323use rustc_mir_dataflow:: move_paths:: { InitKind , MoveOutIndex , MovePathIndex } ;
2424use rustc_span:: hygiene:: DesugaringKind ;
2525use rustc_span:: symbol:: sym;
26- use rustc_span:: { BytePos , Span } ;
26+ use rustc_span:: { BytePos , Span , Symbol } ;
2727use rustc_trait_selection:: infer:: InferCtxtExt ;
2828use rustc_trait_selection:: traits:: TraitEngineExt as _;
2929
@@ -1227,8 +1227,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12271227 from_closure : false ,
12281228 region_name :
12291229 RegionName {
1230- source :
1231- RegionNameSource :: AnonRegionFromUpvar ( upvar_span, ref upvar_name) ,
1230+ source : RegionNameSource :: AnonRegionFromUpvar ( upvar_span, upvar_name) ,
12321231 ..
12331232 } ,
12341233 span,
@@ -1500,7 +1499,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15001499 | BorrowExplanation :: UsedLaterInLoop ( ..)
15011500 | BorrowExplanation :: UsedLaterWhenDropped { .. } => {
15021501 // Only give this note and suggestion if it could be relevant.
1503- err. note ( "consider using a `let` binding to create a longer lived value" ) ;
1502+ let sm = self . infcx . tcx . sess . source_map ( ) ;
1503+ let mut suggested = false ;
1504+ let msg = "consider using a `let` binding to create a longer lived value" ;
1505+
1506+ /// We check that there's a single level of block nesting to ensure always correct
1507+ /// suggestions. If we don't, then we only provide a free-form message to avoid
1508+ /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`.
1509+ /// We could expand the analysis to suggest hoising all of the relevant parts of
1510+ /// the users' code to make the code compile, but that could be too much.
1511+ struct NestedStatementVisitor {
1512+ span : Span ,
1513+ current : usize ,
1514+ found : usize ,
1515+ }
1516+
1517+ impl < ' tcx > Visitor < ' tcx > for NestedStatementVisitor {
1518+ fn visit_block ( & mut self , block : & hir:: Block < ' tcx > ) {
1519+ self . current += 1 ;
1520+ walk_block ( self , block) ;
1521+ self . current -= 1 ;
1522+ }
1523+ fn visit_expr ( & mut self , expr : & hir:: Expr < ' tcx > ) {
1524+ if self . span == expr. span {
1525+ self . found = self . current ;
1526+ }
1527+ walk_expr ( self , expr) ;
1528+ }
1529+ }
1530+ let source_info = self . body . source_info ( location) ;
1531+ if let Some ( scope) = self . body . source_scopes . get ( source_info. scope )
1532+ && let ClearCrossCrate :: Set ( scope_data) = & scope. local_data
1533+ && let Some ( node) = self . infcx . tcx . hir ( ) . find ( scope_data. lint_root )
1534+ && let Some ( id) = node. body_id ( )
1535+ && let hir:: ExprKind :: Block ( block, _) = self . infcx . tcx . hir ( ) . body ( id) . value . kind
1536+ {
1537+ for stmt in block. stmts {
1538+ let mut visitor = NestedStatementVisitor {
1539+ span : proper_span,
1540+ current : 0 ,
1541+ found : 0 ,
1542+ } ;
1543+ visitor. visit_stmt ( stmt) ;
1544+ if visitor. found == 0
1545+ && stmt. span . contains ( proper_span)
1546+ && let Some ( p) = sm. span_to_margin ( stmt. span )
1547+ && let Ok ( s) = sm. span_to_snippet ( proper_span)
1548+ {
1549+ let addition = format ! ( "let binding = {};\n {}" , s, " " . repeat( p) ) ;
1550+ err. multipart_suggestion_verbose (
1551+ msg,
1552+ vec ! [
1553+ ( stmt. span. shrink_to_lo( ) , addition) ,
1554+ ( proper_span, "binding" . to_string( ) ) ,
1555+ ] ,
1556+ Applicability :: MaybeIncorrect ,
1557+ ) ;
1558+ suggested = true ;
1559+ break ;
1560+ }
1561+ }
1562+ }
1563+ if !suggested {
1564+ err. note ( msg) ;
1565+ }
15041566 }
15051567 _ => { }
15061568 }
@@ -1699,7 +1761,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16991761 borrow_span : Span ,
17001762 name : & Option < String > ,
17011763 upvar_span : Span ,
1702- upvar_name : & str ,
1764+ upvar_name : Symbol ,
17031765 escape_span : Span ,
17041766 ) -> DiagnosticBuilder < ' cx , ErrorGuaranteed > {
17051767 let tcx = self . infcx . tcx ;
@@ -2093,7 +2155,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20932155 }
20942156 StorageDeadOrDrop :: Destructor ( _) => kind,
20952157 } ,
2096- ProjectionElem :: Field ( ..) | ProjectionElem :: Downcast ( ..) => {
2158+ ProjectionElem :: OpaqueCast { .. }
2159+ | ProjectionElem :: Field ( ..)
2160+ | ProjectionElem :: Downcast ( ..) => {
20972161 match place_ty. ty . kind ( ) {
20982162 ty:: Adt ( def, _) if def. has_dtor ( tcx) => {
20992163 // Report the outermost adt with a destructor
0 commit comments