@@ -12,18 +12,22 @@ use borrow_check::borrow_set::BorrowData;
12
12
use borrow_check:: error_reporting:: UseSpans ;
13
13
use borrow_check:: nll:: region_infer:: Cause ;
14
14
use 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 } ;
17
18
use rustc_errors:: DiagnosticBuilder ;
18
19
use syntax_pos:: Span ;
19
- use syntax_pos:: symbol:: Symbol ;
20
20
21
21
mod find_use;
22
22
23
23
pub ( in borrow_check) enum BorrowExplanation < ' tcx > {
24
24
UsedLater ( LaterUseKind , Span ) ,
25
25
UsedLaterInLoop ( LaterUseKind , Span ) ,
26
- UsedLaterWhenDropped ( Span , Symbol , bool ) ,
26
+ UsedLaterWhenDropped {
27
+ drop_loc : Location ,
28
+ dropped_local : Local ,
29
+ should_note_order : bool ,
30
+ } ,
27
31
MustBeValidFor ( Region < ' tcx > ) ,
28
32
Unexplained ,
29
33
}
@@ -40,7 +44,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
40
44
pub ( in borrow_check) fn add_explanation_to_diagnostic < ' cx , ' gcx > (
41
45
& self ,
42
46
tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
43
- _mir : & Mir < ' tcx > ,
47
+ mir : & Mir < ' tcx > ,
44
48
err : & mut DiagnosticBuilder < ' _ > ,
45
49
borrow_desc : & str ,
46
50
) {
@@ -65,23 +69,76 @@ impl<'tcx> BorrowExplanation<'tcx> {
65
69
} ;
66
70
err. span_label ( var_or_use_span, format ! ( "{}{}" , borrow_desc, message) ) ;
67
71
} ,
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
+ } ;
77
135
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
+ }
83
139
}
84
- } ,
140
+ }
141
+
85
142
BorrowExplanation :: MustBeValidFor ( region) => {
86
143
tcx. note_and_explain_free_region (
87
144
err,
@@ -116,8 +173,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
116
173
kind_place : Option < ( WriteKind , & Place < ' tcx > ) > ,
117
174
) -> BorrowExplanation < ' tcx > {
118
175
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
121
178
) ;
122
179
123
180
let regioncx = & self . nonlexical_regioncx ;
@@ -154,32 +211,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
154
211
}
155
212
}
156
213
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 ;
165
222
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
+ }
180
231
181
- None => BorrowExplanation :: Unexplained ,
182
- } ,
232
+ BorrowExplanation :: UsedLaterWhenDropped {
233
+ drop_loc : location,
234
+ dropped_local : local,
235
+ should_note_order,
236
+ }
237
+ }
183
238
184
239
None => if let Some ( region) = regioncx. to_error_region ( region_sub) {
185
240
BorrowExplanation :: MustBeValidFor ( region)
0 commit comments