From 4e706f56bd3beb0833d9e05b0dabdc3c3ce750e4 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 26 Aug 2018 22:50:57 -0400 Subject: [PATCH] [nll] teach SCC about `'static` Fixes #53178 --- .../borrow_check/nll/constraints/graph.rs | 70 ++++++++++++++++--- .../borrow_check/nll/constraints/mod.rs | 3 +- .../nll/region_infer/error_reporting/mod.rs | 5 +- .../borrow_check/nll/region_infer/mod.rs | 3 +- .../nll/type_check/liveness/mod.rs | 3 +- 5 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/nll/constraints/graph.rs index 7cf94ec84dc9..b1e8b974379d 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/graph.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use borrow_check::nll::type_check::Locations; use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSet, OutlivesConstraint}; use rustc::ty::RegionVid; use rustc_data_structures::graph; @@ -31,6 +32,7 @@ crate type ReverseConstraintGraph = ConstraintGraph; crate trait ConstraintGraphDirecton: Copy + 'static { fn start_region(c: &OutlivesConstraint) -> RegionVid; fn end_region(c: &OutlivesConstraint) -> RegionVid; + fn is_normal() -> bool; } /// In normal mode, a `R1: R2` constraint results in an edge `R1 -> @@ -48,6 +50,10 @@ impl ConstraintGraphDirecton for Normal { fn end_region(c: &OutlivesConstraint) -> RegionVid { c.sub } + + fn is_normal() -> bool { + true + } } /// In reverse mode, a `R1: R2` constraint results in an edge `R2 -> @@ -65,6 +71,10 @@ impl ConstraintGraphDirecton for Reverse { fn end_region(c: &OutlivesConstraint) -> RegionVid { c.sup } + + fn is_normal() -> bool { + false + } } impl ConstraintGraph { @@ -98,8 +108,12 @@ impl ConstraintGraph { /// Given the constraint set from which this graph was built /// creates a region graph so that you can iterate over *regions* /// and not constraints. - crate fn region_graph<'rg>(&'rg self, set: &'rg ConstraintSet) -> RegionGraph<'rg, D> { - RegionGraph::new(set, self) + crate fn region_graph<'rg>( + &'rg self, + set: &'rg ConstraintSet, + static_region: RegionVid, + ) -> RegionGraph<'rg, D> { + RegionGraph::new(set, self, static_region) } /// Given a region `R`, iterate over all constraints `R: R1`. @@ -107,12 +121,28 @@ impl ConstraintGraph { &'a self, region_sup: RegionVid, constraints: &'a ConstraintSet, + static_region: RegionVid, ) -> Edges<'a, D> { - let first = self.first_constraints[region_sup]; - Edges { - graph: self, - constraints, - pointer: first, + //if this is the `'static` region and the graph's direction is normal, + //then setup the Edges iterator to return all regions #53178 + if region_sup == static_region && D::is_normal() { + Edges { + graph: self, + constraints, + pointer: None, + next_static_idx: Some(0), + static_region, + } + } else { + //otherwise, just setup the iterator as normal + let first = self.first_constraints[region_sup]; + Edges { + graph: self, + constraints, + pointer: first, + next_static_idx: None, + static_region, + } } } } @@ -121,6 +151,8 @@ crate struct Edges<'s, D: ConstraintGraphDirecton> { graph: &'s ConstraintGraph, constraints: &'s ConstraintSet, pointer: Option, + next_static_idx: Option, + static_region: RegionVid, } impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { @@ -129,7 +161,21 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { fn next(&mut self) -> Option { if let Some(p) = self.pointer { self.pointer = self.graph.next_constraints[p]; + Some(self.constraints[p]) + } else if let Some(next_static_idx) = self.next_static_idx { + self.next_static_idx = + if next_static_idx == (self.graph.first_constraints.len() - 1) { + None + } else { + Some(next_static_idx + 1) + }; + + Some(OutlivesConstraint { + sup: self.static_region, + sub: next_static_idx.into(), + locations: Locations::All, + }) } else { None } @@ -142,6 +188,7 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { crate struct RegionGraph<'s, D: ConstraintGraphDirecton> { set: &'s ConstraintSet, constraint_graph: &'s ConstraintGraph, + static_region: RegionVid, } impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> { @@ -149,10 +196,15 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> { /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. - crate fn new(set: &'s ConstraintSet, constraint_graph: &'s ConstraintGraph) -> Self { + crate fn new( + set: &'s ConstraintSet, + constraint_graph: &'s ConstraintGraph, + static_region: RegionVid, + ) -> Self { Self { set, constraint_graph, + static_region, } } @@ -160,7 +212,7 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> { /// there exists a constraint `R: R1`. crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> { Successors { - edges: self.constraint_graph.outgoing_edges(region_sup, self.set), + edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), } } } diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index 4cb92262ff08..9a8b0f391de9 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -58,8 +58,9 @@ impl ConstraintSet { crate fn compute_sccs( &self, constraint_graph: &graph::NormalConstraintGraph, + static_region: RegionVid, ) -> Sccs { - let region_graph = &constraint_graph.region_graph(self); + let region_graph = &constraint_graph.region_graph(self, static_region); Sccs::new(region_graph) } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 2a541b6474f5..0b9b9b33b3f1 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -201,7 +201,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Otherwise, walk over the outgoing constraints and // enqueue any regions we find, keeping track of how we // reached them. - for constraint in self.constraint_graph.outgoing_edges(r, &self.constraints) { + let fr_static = self.universal_regions.fr_static; + for constraint in self.constraint_graph.outgoing_edges(r, + &self.constraints, + fr_static) { assert_eq!(constraint.sup, r); let sub_region = constraint.sub; if let Trace::NotVisited = context[sub_region] { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 4fe39ba3c952..bbdf2a929221 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -234,7 +234,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { let constraints = Rc::new(outlives_constraints); // freeze constraints let constraint_graph = Rc::new(constraints.graph(definitions.len())); - let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph)); + let fr_static = universal_regions.fr_static; + let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); let mut scc_values = RegionValues::new(elements, universal_regions.len(), max_universe); diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index b3fc73e9b7be..357e9ee72102 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -69,7 +69,8 @@ fn regions_that_outlive_free_regions( // reachable from each free region, we will have all the // regions that are forced to outlive some free region. let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars); - let rev_region_graph = rev_constraint_graph.region_graph(constraint_set); + let fr_static = universal_regions.fr_static; + let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static); // Stack for the depth-first search. Start out with all the free regions. let mut stack: Vec<_> = universal_regions.universal_regions().collect();