@@ -12,18 +12,22 @@ use borrow_check::borrow_set::BorrowData;
1212use borrow_check:: error_reporting:: UseSpans ;
1313use borrow_check:: nll:: region_infer:: Cause ;
1414use borrow_check:: { Context , MirBorrowckCtxt , WriteKind } ;
15- use rustc:: ty:: { Region , TyCtxt } ;
16- use rustc:: mir:: { FakeReadCause , Location , Mir , Operand , Place , StatementKind , TerminatorKind } ;
15+ use rustc:: ty:: { self , Region , TyCtxt } ;
16+ use rustc:: mir:: { FakeReadCause , Local , Location , Mir , Operand } ;
17+ use rustc:: mir:: { Place , StatementKind , TerminatorKind } ;
1718use rustc_errors:: DiagnosticBuilder ;
1819use syntax_pos:: Span ;
19- use syntax_pos:: symbol:: Symbol ;
2020
2121mod find_use;
2222
2323pub ( in borrow_check) enum BorrowExplanation < ' tcx > {
2424 UsedLater ( LaterUseKind , Span ) ,
2525 UsedLaterInLoop ( LaterUseKind , Span ) ,
26- UsedLaterWhenDropped ( Span , Symbol , bool ) ,
26+ UsedLaterWhenDropped {
27+ drop_loc : Location ,
28+ dropped_local : Local ,
29+ should_note_order : bool ,
30+ } ,
2731 MustBeValidFor ( Region < ' tcx > ) ,
2832 Unexplained ,
2933}
@@ -40,7 +44,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
4044 pub ( in borrow_check) fn add_explanation_to_diagnostic < ' cx , ' gcx > (
4145 & self ,
4246 tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
43- _mir : & Mir < ' tcx > ,
47+ mir : & Mir < ' tcx > ,
4448 err : & mut DiagnosticBuilder < ' _ > ,
4549 borrow_desc : & str ,
4650 ) {
@@ -65,23 +69,76 @@ impl<'tcx> BorrowExplanation<'tcx> {
6569 } ;
6670 err. span_label ( var_or_use_span, format ! ( "{}{}" , borrow_desc, message) ) ;
6771 } ,
68- BorrowExplanation :: UsedLaterWhenDropped ( span, local_name, should_note_order) => {
69- err. span_label (
70- span,
71- format ! (
72- "{}borrow later used here, when `{}` is dropped" ,
73- borrow_desc,
74- local_name,
75- ) ,
76- ) ;
72+ BorrowExplanation :: UsedLaterWhenDropped { drop_loc, dropped_local,
73+ should_note_order } =>
74+ {
75+ let local_decl = & mir. local_decls [ dropped_local] ;
76+ let ( dtor_desc, type_desc) = match local_decl. ty . sty {
77+ // If type is an ADT that implements Drop, then
78+ // simplify output by reporting just the ADT name.
79+ ty:: Adt ( adt, _substs) if adt. has_dtor ( tcx) && !adt. is_box ( ) =>
80+ ( "`Drop` code" , format ! ( "type `{}`" , tcx. item_path_str( adt. did) ) ) ,
81+
82+ // Otherwise, just report the whole type (and use
83+ // the intentionally fuzzy phrase "destructor")
84+ ty:: Closure ( ..) =>
85+ ( "destructor" , format ! ( "closure" ) ) ,
86+ ty:: Generator ( ..) =>
87+ ( "destructor" , format ! ( "generator" ) ) ,
88+
89+ _ => ( "destructor" , format ! ( "type `{}`" , local_decl. ty) ) ,
90+ } ;
91+
92+ match local_decl. name {
93+ Some ( local_name) => {
94+ let message =
95+ format ! ( "{B}borrow might be used here, when `{LOC}` is dropped \
96+ and runs the {DTOR} for {TYPE}",
97+ B =borrow_desc, LOC =local_name, TYPE =type_desc, DTOR =dtor_desc) ;
98+ err. span_label ( mir. source_info ( drop_loc) . span , message) ;
99+
100+ if should_note_order {
101+ err. note (
102+ "values in a scope are dropped \
103+ in the opposite order they are defined",
104+ ) ;
105+ }
106+ }
107+ None => {
108+ err. span_label ( local_decl. source_info . span ,
109+ format ! ( "a temporary with access to the {B}borrow \
110+ is created here ...",
111+ B =borrow_desc) ) ;
112+ let message =
113+ format ! ( "... and the {B}borrow might be used here, \
114+ when that temporary is dropped \
115+ and runs the {DTOR} for {TYPE}",
116+ B =borrow_desc, TYPE =type_desc, DTOR =dtor_desc) ;
117+ err. span_label ( mir. source_info ( drop_loc) . span , message) ;
118+
119+ if let Some ( info) = & local_decl. is_block_tail {
120+ // FIXME: use span_suggestion instead, highlighting the
121+ // whole block tail expression.
122+ let msg = if info. tail_result_is_ignored {
123+ "The temporary is part of an expression at the end of a block. \
124+ Consider adding semicolon after the expression so its temporaries \
125+ are dropped sooner, before the local variables declared by the \
126+ block are dropped."
127+ } else {
128+ "The temporary is part of an expression at the end of a block. \
129+ Consider forcing this temporary to be dropped sooner, before \
130+ the block's local variables are dropped. \
131+ For example, you could save the expression's value in a new \
132+ local variable `x` and then make `x` be the expression \
133+ at the end of the block."
134+ } ;
77135
78- if should_note_order {
79- err. note (
80- "values in a scope are dropped \
81- in the opposite order they are defined",
82- ) ;
136+ err. note ( msg) ;
137+ }
138+ }
83139 }
84- } ,
140+ }
141+
85142 BorrowExplanation :: MustBeValidFor ( region) => {
86143 tcx. note_and_explain_free_region (
87144 err,
@@ -116,8 +173,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
116173 kind_place : Option < ( WriteKind , & Place < ' tcx > ) > ,
117174 ) -> BorrowExplanation < ' tcx > {
118175 debug ! (
119- "explain_why_borrow_contains_point(context={:?}, borrow={:?})" ,
120- context, borrow,
176+ "explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?} )" ,
177+ context, borrow, kind_place
121178 ) ;
122179
123180 let regioncx = & self . nonlexical_regioncx ;
@@ -154,32 +211,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
154211 }
155212 }
156213
157- Some ( Cause :: DropVar ( local, location) ) => match & mir . local_decls [ local ] . name {
158- Some ( local_name ) => {
159- let mut should_note_order = false ;
160- if let Some ( ( WriteKind :: StorageDeadOrDrop , place) ) = kind_place {
161- if let Place :: Local ( borrowed_local) = place {
162- let dropped_local_scope = mir. local_decls [ local] . visibility_scope ;
163- let borrowed_local_scope =
164- mir. local_decls [ * borrowed_local] . visibility_scope ;
214+ Some ( Cause :: DropVar ( local, location) ) => {
215+ let mut should_note_order = false ;
216+ if mir . local_decls [ local ] . name . is_some ( ) {
217+ if let Some ( ( WriteKind :: StorageDeadOrDrop , place) ) = kind_place {
218+ if let Place :: Local ( borrowed_local) = place {
219+ let dropped_local_scope = mir. local_decls [ local] . visibility_scope ;
220+ let borrowed_local_scope =
221+ mir. local_decls [ * borrowed_local] . visibility_scope ;
165222
166- if mir. is_sub_scope ( borrowed_local_scope, dropped_local_scope)
167- && local != * borrowed_local
168- {
169- should_note_order = true ;
170- }
171- }
172- }
173-
174- BorrowExplanation :: UsedLaterWhenDropped (
175- mir. source_info ( location) . span ,
176- * local_name,
177- should_note_order
178- )
179- } ,
223+ if mir. is_sub_scope ( borrowed_local_scope, dropped_local_scope)
224+ && local != * borrowed_local
225+ {
226+ should_note_order = true ;
227+ }
228+ }
229+ }
230+ }
180231
181- None => BorrowExplanation :: Unexplained ,
182- } ,
232+ BorrowExplanation :: UsedLaterWhenDropped {
233+ drop_loc : location,
234+ dropped_local : local,
235+ should_note_order,
236+ }
237+ }
183238
184239 None => if let Some ( region) = regioncx. to_error_region ( region_sub) {
185240 BorrowExplanation :: MustBeValidFor ( region)
0 commit comments