about summary refs log tree commit diff
path: root/compiler/rustc_borrowck/src
diff options
context:
space:
mode:
authorRémy Rakic <remy.rakic+github@gmail.com>2023-11-04 00:55:27 +0000
committerRémy Rakic <remy.rakic+github@gmail.com>2023-11-04 01:04:12 +0000
commitde7a8305ae2b6eef11133de783f5089a94928f79 (patch)
tree14549c3957f84b88940d9141143423f4adea9aeb /compiler/rustc_borrowck/src
parent5020f7c3b8bd8bf57077389bca5c19f7911fde7a (diff)
downloadrust-de7a8305ae2b6eef11133de783f5089a94928f79.tar.gz
rust-de7a8305ae2b6eef11133de783f5089a94928f79.zip
traverse region graph instead of SCCs to compute polonius loan scopes
By using SCC for better performance, we also have to take into account
SCCs whose representative is an existential region but also contains a
placeholder.

By only checking the representative, we may miss that the loan escapes
the function. This can be fixed by picking a better representative, or
removing placeholders from the main path.

This is the simplest fix: forgo efficiency and traverse the region graph
instead of the SCCs.
Diffstat (limited to 'compiler/rustc_borrowck/src')
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs21
2 files changed, 14 insertions, 13 deletions
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 16814950b0d..8676d2ba7c4 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -273,11 +273,10 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
     ) {
         let sccs = self.regioncx.constraint_sccs();
         let universal_regions = self.regioncx.universal_regions();
-        let issuing_region_scc = sccs.scc(issuing_region);
 
         // We first handle the cases where the loan doesn't go out of scope, depending on the issuing
         // region's successors.
-        for scc in sccs.depth_first_search(issuing_region_scc) {
+        for successor in self.regioncx.region_graph().depth_first_search(issuing_region) {
             // 1. Via applied member constraints
             //
             // The issuing region can flow into the choice regions, and they are either:
@@ -290,6 +289,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
             // For additional insurance via fuzzing and crater, we verify that the constraint's min
             // choice indeed escapes the function. In the future, we could e.g. turn this check into
             // a debug assert and early return as an optimization.
+            let scc = sccs.scc(successor);
             for constraint in self.regioncx.applied_member_constraints(scc) {
                 if universal_regions.is_universal_region(constraint.min_choice) {
                     return;
@@ -300,7 +300,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
             //
             // If the issuing region outlives such a region, its loan escapes the function and
             // cannot go out of scope. We can early return.
-            if self.regioncx.scc_is_live_at_all_points(scc) {
+            if self.regioncx.is_region_live_at_all_points(successor) {
                 return;
             }
         }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 05c2cbd4969..b1f91a05628 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -22,11 +22,10 @@ use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::Span;
 
+use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
 use crate::dataflow::BorrowIndex;
 use crate::{
-    constraints::{
-        graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
-    },
+    constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet},
     diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
     member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
     nll::PoloniusOutput,
@@ -2293,19 +2292,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         self.constraint_sccs.as_ref()
     }
 
-    /// Returns whether the given SCC is live at all points: whether the representative is a
+    /// Access to the region graph, built from the outlives constraints.
+    pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> {
+        self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static)
+    }
+
+    /// Returns whether the given region is considered live at all points: whether it is a
     /// placeholder or a free region.
-    pub(crate) fn scc_is_live_at_all_points(&self, scc: ConstraintSccIndex) -> bool {
+    pub(crate) fn is_region_live_at_all_points(&self, region: RegionVid) -> bool {
         // FIXME: there must be a cleaner way to find this information. At least, when
         // higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
         // need to check whether this is a universal region.
-        let representative = self.scc_representatives[scc];
-        let origin = self.var_infos[representative].origin;
+        let origin = self.region_definition(region).origin;
         let live_at_all_points = matches!(
             origin,
-            RegionVariableOrigin::Nll(
-                NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
-            )
+            NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
         );
         live_at_all_points
     }