@@ -17,6 +17,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1717use rustc_data_structures:: fx:: FxHashSet ;
1818use std:: collections:: BTreeSet ;
1919use std:: fmt;
20+ use syntax_pos:: Span ;
2021
2122pub struct RegionInferenceContext < ' tcx > {
2223 /// Contains the definition for every region variable. Region
@@ -70,10 +71,11 @@ struct Region {
7071
7172impl fmt:: Debug for Region {
7273 fn fmt ( & self , formatter : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
73- formatter. debug_set ( )
74- . entries ( & self . points )
75- . entries ( & self . free_regions )
76- . finish ( )
74+ formatter
75+ . debug_set ( )
76+ . entries ( & self . points )
77+ . entries ( & self . free_regions )
78+ . finish ( )
7779 }
7880}
7981
@@ -93,8 +95,16 @@ impl Region {
9395
9496#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
9597pub struct Constraint {
96- sub : RegionIndex ,
98+ /// Where did this constraint arise?
99+ span : Span ,
100+
101+ /// The region SUP must outlive SUB...
97102 sup : RegionIndex ,
103+
104+ /// Region that must be outlived.
105+ sub : RegionIndex ,
106+
107+ /// At this location.
98108 point : Location ,
99109}
100110
@@ -210,56 +220,116 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
210220 pub ( super ) fn add_live_point ( & mut self , v : RegionIndex , point : Location ) {
211221 debug ! ( "add_live_point({:?}, {:?})" , v, point) ;
212222 let definition = & mut self . definitions [ v] ;
213- definition. value . add_point ( point) ;
223+ if !definition. constant {
224+ definition. value . add_point ( point) ;
225+ } else {
226+ // Constants are used for free regions, which already
227+ // contain all the points in the control-flow graph.
228+ assert ! ( definition. value. contains_point( point) ) ;
229+ }
214230 }
215231
216232 /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
217- pub ( super ) fn add_outlives ( & mut self , sup : RegionIndex , sub : RegionIndex , point : Location ) {
233+ pub ( super ) fn add_outlives (
234+ & mut self ,
235+ span : Span ,
236+ sup : RegionIndex ,
237+ sub : RegionIndex ,
238+ point : Location ,
239+ ) {
218240 debug ! ( "add_outlives({:?}: {:?} @ {:?}" , sup, sub, point) ;
219- self . constraints . push ( Constraint { sup, sub, point } ) ;
241+ self . constraints . push ( Constraint {
242+ span,
243+ sup,
244+ sub,
245+ point,
246+ } ) ;
220247 }
221248
222249 /// Perform region inference.
223250 pub ( super ) fn solve ( & mut self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , mir : & Mir < ' tcx > ) {
224- self . propagate_constraints ( infcx, mir) ;
251+ let errors = self . propagate_constraints ( mir) ;
252+
253+ // worst error msg ever
254+ for ( fr1, span, fr2) in errors {
255+ infcx. tcx . sess . span_err (
256+ span,
257+ & format ! (
258+ "free region `{}` does not outlive `{}`" ,
259+ self . definitions[ fr1] . name. unwrap( ) ,
260+ self . definitions[ fr2] . name. unwrap( )
261+ ) ,
262+ ) ;
263+ }
225264 }
226265
227266 /// Propagate the region constraints: this will grow the values
228267 /// for each region variable until all the constraints are
229268 /// satisfied. Note that some values may grow **too** large to be
230269 /// feasible, but we check this later.
231- fn propagate_constraints ( & mut self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , mir : & Mir < ' tcx > ) {
270+ fn propagate_constraints (
271+ & mut self ,
272+ mir : & Mir < ' tcx > ,
273+ ) -> Vec < ( RegionIndex , Span , RegionIndex ) > {
232274 let mut changed = true ;
233- let mut dfs = Dfs :: new ( infcx, mir) ;
275+ let mut dfs = Dfs :: new ( mir) ;
276+ let mut error_regions = FxHashSet ( ) ;
277+ let mut errors = vec ! [ ] ;
234278 while changed {
235279 changed = false ;
236280 for constraint in & self . constraints {
281+ debug ! ( "constraint: {:?}" , constraint) ;
237282 let sub = & self . definitions [ constraint. sub ] . value . clone ( ) ;
238283 let sup_def = & mut self . definitions [ constraint. sup ] ;
239- debug ! ( "constraint: {:?}" , constraint ) ;
284+
240285 debug ! ( " sub (before): {:?}" , sub) ;
241286 debug ! ( " sup (before): {:?}" , sup_def. value) ;
242287
243- if dfs. copy ( sub, & mut sup_def. value , constraint. point ) {
244- changed = true ;
288+ if !sup_def. constant {
289+ // If this is not a constant, then grow the value as needed to
290+ // accommodate the outlives constraint.
291+
292+ if dfs. copy ( sub, & mut sup_def. value , constraint. point ) {
293+ changed = true ;
294+ }
295+
296+ debug ! ( " sup (after) : {:?}" , sup_def. value) ;
297+ debug ! ( " changed : {:?}" , changed) ;
298+ } else {
299+ // If this is a constant, check whether it *would
300+ // have* to grow in order for the constraint to be
301+ // satisfied. If so, create an error.
302+
303+ let mut sup_value = sup_def. value . clone ( ) ;
304+ if dfs. copy ( sub, & mut sup_value, constraint. point ) {
305+ // Constant values start out with the entire
306+ // CFG, so it must be some new free region
307+ // that was added. Find one.
308+ let & new_region = sup_value
309+ . free_regions
310+ . difference ( & sup_def. value . free_regions )
311+ . next ( )
312+ . unwrap ( ) ;
313+ debug ! ( " new_region : {:?}" , new_region) ;
314+ if error_regions. insert ( constraint. sup ) {
315+ errors. push ( ( constraint. sup , constraint. span , new_region) ) ;
316+ }
317+ }
245318 }
246-
247- debug ! ( " sup (after) : {:?}" , sup_def. value) ;
248- debug ! ( " changed : {:?}" , changed) ;
249319 }
250320 debug ! ( "\n " ) ;
251321 }
322+ errors
252323 }
253324}
254325
255- struct Dfs < ' a , ' gcx : ' tcx + ' a , ' tcx : ' a > {
256- #[ allow( dead_code) ] infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
326+ struct Dfs < ' a , ' tcx : ' a > {
257327 mir : & ' a Mir < ' tcx > ,
258328}
259329
260- impl < ' a , ' gcx : ' tcx , ' tcx : ' a > Dfs < ' a , ' gcx , ' tcx > {
261- fn new ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > , mir : & ' a Mir < ' tcx > ) -> Self {
262- Self { infcx , mir }
330+ impl < ' a , ' tcx > Dfs < ' a , ' tcx > {
331+ fn new ( mir : & ' a Mir < ' tcx > ) -> Self {
332+ Self { mir }
263333 }
264334
265335 fn copy (
@@ -316,7 +386,10 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
316386 // over any skolemized end points in the `from_region`
317387 // and make sure they are included in the `to_region`.
318388
319- to_region. free_regions . extend ( & from_region. free_regions ) ;
389+ debug ! ( " dfs: free_regions={:?}" , from_region. free_regions) ;
390+ for & fr in & from_region. free_regions {
391+ changed |= to_region. free_regions . insert ( fr) ;
392+ }
320393 } else {
321394 stack. extend ( successor_points) ;
322395 }
0 commit comments