11
11
use borrow_check:: borrow_set:: BorrowData ;
12
12
use borrow_check:: nll:: region_infer:: Cause ;
13
13
use borrow_check:: { Context , MirBorrowckCtxt , WriteKind } ;
14
- use rustc:: mir:: { Location , Place , TerminatorKind } ;
14
+ use rustc:: mir:: { Local , Location , Place , TerminatorKind } ;
15
15
use rustc_errors:: DiagnosticBuilder ;
16
+ use rustc:: ty:: Region ;
16
17
17
18
mod find_use;
18
19
20
+ #[ derive( Copy , Clone , Debug ) ]
21
+ pub enum BorrowContainsPointReason < ' tcx > {
22
+ Liveness {
23
+ local : Local ,
24
+ location : Location ,
25
+ in_loop : bool ,
26
+ } ,
27
+ DropLiveness {
28
+ local : Local ,
29
+ location : Location ,
30
+ } ,
31
+ OutlivesFreeRegion {
32
+ outlived_region : Option < Region < ' tcx > > ,
33
+ } ,
34
+ }
35
+
19
36
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
20
37
/// Adds annotations to `err` explaining *why* the borrow contains the
21
38
/// point from `context`. This is key for the "3-point errors"
@@ -32,15 +49,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
32
49
///
33
50
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
34
51
pub ( in borrow_check) fn explain_why_borrow_contains_point (
35
- & mut self ,
52
+ & self ,
36
53
context : Context ,
37
54
borrow : & BorrowData < ' tcx > ,
38
55
kind_place : Option < ( WriteKind , & Place < ' tcx > ) > ,
39
56
err : & mut DiagnosticBuilder < ' _ > ,
40
57
) {
58
+ let reason = self . find_why_borrow_contains_point ( context, borrow) ;
59
+ self . report_why_borrow_contains_point ( err, reason, kind_place) ;
60
+ }
61
+
62
+ /// Finds the reason that [explain_why_borrow_contains_point] will report
63
+ /// but doesn't add it to any message. This is a separate function in case
64
+ /// the caller wants to change the error they report based on the reason
65
+ /// that will be reported.
66
+ pub ( in borrow_check) fn find_why_borrow_contains_point (
67
+ & self ,
68
+ context : Context ,
69
+ borrow : & BorrowData < ' tcx >
70
+ ) -> BorrowContainsPointReason < ' tcx > {
71
+ use self :: BorrowContainsPointReason :: * ;
72
+
41
73
debug ! (
42
- "explain_why_borrow_contains_point (context={:?}, borrow={:?}, kind_place ={:?})" ,
43
- context, borrow, kind_place ,
74
+ "find_why_borrow_contains_point (context={:?}, borrow={:?})" ,
75
+ context, borrow,
44
76
) ;
45
77
46
78
let regioncx = & self . nonlexical_regioncx ;
@@ -62,11 +94,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
62
94
) ;
63
95
64
96
match find_use:: find ( mir, regioncx, tcx, region_sub, context. loc ) {
65
- Some ( Cause :: LiveVar ( local, location) ) => {
97
+ Some ( Cause :: LiveVar ( local, location) ) => Liveness {
98
+ local,
99
+ location,
100
+ in_loop : self . is_borrow_location_in_loop ( context. loc ) ,
101
+ } ,
102
+ Some ( Cause :: DropVar ( local, location) ) => DropLiveness {
103
+ local,
104
+ location,
105
+ } ,
106
+ None => OutlivesFreeRegion {
107
+ outlived_region : regioncx. to_error_region ( region_sub) ,
108
+ } ,
109
+ }
110
+ }
111
+
112
+ /// Adds annotations to `err` for the explanation `reason`. This is a
113
+ /// separate method so that the caller can change their error message based
114
+ /// on the reason that is going to be reported.
115
+ pub ( in borrow_check) fn report_why_borrow_contains_point (
116
+ & self ,
117
+ err : & mut DiagnosticBuilder ,
118
+ reason : BorrowContainsPointReason < ' tcx > ,
119
+ kind_place : Option < ( WriteKind , & Place < ' tcx > ) > ,
120
+ ) {
121
+ use self :: BorrowContainsPointReason :: * ;
122
+
123
+ debug ! (
124
+ "find_why_borrow_contains_point(reason={:?}, kind_place={:?})" ,
125
+ reason, kind_place,
126
+ ) ;
127
+
128
+ let mir = self . mir ;
129
+
130
+ match reason {
131
+ Liveness { local, location, in_loop } => {
66
132
let span = mir. source_info ( location) . span ;
67
133
let spans = self . move_spans ( & Place :: Local ( local) , location)
68
134
. or_else ( || self . borrow_spans ( span, location) ) ;
69
- let message = if self . is_borrow_location_in_loop ( context . loc ) {
135
+ let message = if in_loop {
70
136
if spans. for_closure ( ) {
71
137
"borrow captured here by closure in later iteration of loop"
72
138
} else {
@@ -81,8 +147,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
81
147
} ;
82
148
err. span_label ( spans. var_or_use ( ) , message) ;
83
149
}
84
-
85
- Some ( Cause :: DropVar ( local, location) ) => match & mir. local_decls [ local] . name {
150
+ DropLiveness { local, location } => match & mir. local_decls [ local] . name {
86
151
Some ( local_name) => {
87
152
err. span_label (
88
153
mir. source_info ( location) . span ,
@@ -93,31 +158,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
93
158
if let Place :: Local ( borrowed_local) = place {
94
159
let dropped_local_scope = mir. local_decls [ local] . visibility_scope ;
95
160
let borrowed_local_scope =
96
- mir. local_decls [ * borrowed_local] . visibility_scope ;
161
+ mir. local_decls [ * borrowed_local] . visibility_scope ;
97
162
98
163
if mir. is_sub_scope ( borrowed_local_scope, dropped_local_scope) {
99
164
err. note (
100
- "values in a scope are dropped \
101
- in the opposite order they are defined",
165
+ "values in a scope are dropped \
166
+ in the opposite order they are defined",
102
167
) ;
103
168
}
104
169
}
105
170
}
106
171
}
107
172
108
173
None => { }
109
- } ,
110
-
111
- None => {
112
- if let Some ( region) = regioncx. to_error_region ( region_sub) {
113
- self . tcx . note_and_explain_free_region (
114
- err,
115
- "borrowed value must be valid for " ,
116
- region,
117
- "..." ,
118
- ) ;
119
- }
120
174
}
175
+ OutlivesFreeRegion { outlived_region : Some ( region) } => {
176
+ self . tcx . note_and_explain_free_region (
177
+ err,
178
+ "borrowed value must be valid for " ,
179
+ region,
180
+ "..." ,
181
+ ) ;
182
+ }
183
+ OutlivesFreeRegion { outlived_region : None } => ( ) ,
121
184
}
122
185
}
123
186
@@ -193,3 +256,4 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
193
256
false
194
257
}
195
258
}
259
+
0 commit comments