1111use borrow_check:: borrow_set:: BorrowData ;
1212use borrow_check:: nll:: region_infer:: Cause ;
1313use borrow_check:: { Context , MirBorrowckCtxt , WriteKind } ;
14- use rustc:: mir:: { Location , Place , TerminatorKind } ;
14+ use rustc:: mir:: { Local , Location , Place , TerminatorKind } ;
1515use rustc_errors:: DiagnosticBuilder ;
16+ use rustc:: ty:: Region ;
1617
1718mod find_use;
1819
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+
1936impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
2037 /// Adds annotations to `err` explaining *why* the borrow contains the
2138 /// point from `context`. This is key for the "3-point errors"
@@ -32,15 +49,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
3249 ///
3350 /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
3451 pub ( in borrow_check) fn explain_why_borrow_contains_point (
35- & mut self ,
52+ & self ,
3653 context : Context ,
3754 borrow : & BorrowData < ' tcx > ,
3855 kind_place : Option < ( WriteKind , & Place < ' tcx > ) > ,
3956 err : & mut DiagnosticBuilder < ' _ > ,
4057 ) {
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+
4173 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,
4476 ) ;
4577
4678 let regioncx = & self . nonlexical_regioncx ;
@@ -62,11 +94,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
6294 ) ;
6395
6496 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 } => {
66132 let span = mir. source_info ( location) . span ;
67133 let spans = self . move_spans ( & Place :: Local ( local) , location)
68134 . 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 {
70136 if spans. for_closure ( ) {
71137 "borrow captured here by closure in later iteration of loop"
72138 } else {
@@ -81,8 +147,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
81147 } ;
82148 err. span_label ( spans. var_or_use ( ) , message) ;
83149 }
84-
85- Some ( Cause :: DropVar ( local, location) ) => match & mir. local_decls [ local] . name {
150+ DropLiveness { local, location } => match & mir. local_decls [ local] . name {
86151 Some ( local_name) => {
87152 err. span_label (
88153 mir. source_info ( location) . span ,
@@ -93,31 +158,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
93158 if let Place :: Local ( borrowed_local) = place {
94159 let dropped_local_scope = mir. local_decls [ local] . visibility_scope ;
95160 let borrowed_local_scope =
96- mir. local_decls [ * borrowed_local] . visibility_scope ;
161+ mir. local_decls [ * borrowed_local] . visibility_scope ;
97162
98163 if mir. is_sub_scope ( borrowed_local_scope, dropped_local_scope) {
99164 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",
102167 ) ;
103168 }
104169 }
105170 }
106171 }
107172
108173 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- }
120174 }
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 } => ( ) ,
121184 }
122185 }
123186
@@ -193,3 +256,4 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
193256 false
194257 }
195258}
259+
0 commit comments