From 771fdd99852ba8465b76674466b470a1ee3dd3c2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Apr 2020 11:23:30 +0000 Subject: [PATCH 1/5] enforce that R1: R2 requires univ(R1) <= univ(R2) --- .../borrow_check/region_infer/mod.rs | 84 +++++++++++++++++-- .../impl-fn-ignore-binder-via-bottom.rs | 36 ++++++++ .../impl-fn-ignore-binder-via-bottom.stderr | 20 +++++ .../ui/nll/type-check-pointer-comparisons.rs | 8 +- .../nll/type-check-pointer-comparisons.stderr | 14 +++- 5 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs create mode 100644 src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 400121166335f..9533d61b7e83e 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -321,10 +321,75 @@ impl<'tcx> RegionInferenceContext<'tcx> { let num_sccs = constraints_scc.num_sccs(); let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs); + debug!("compute_scc_universes()"); + + // For each region R in universe U, ensure that the universe for the SCC + // that contains R is "no bigger" than U. This effectively sets the universe + // for each SCC to be the minimum of the regions within. for (region_vid, region_definition) in definitions.iter_enumerated() { let scc = constraints_scc.scc(region_vid); let scc_universe = &mut scc_universes[scc]; - *scc_universe = ::std::cmp::min(*scc_universe, region_definition.universe); + let scc_min = std::cmp::min(region_definition.universe, *scc_universe); + if scc_min != *scc_universe { + *scc_universe = scc_min; + debug!( + "compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \ + because it contains {region_vid:?} in {region_universe:?}", + scc = scc, + scc_min = scc_min, + region_vid = region_vid, + region_universe = region_definition.universe, + ); + } + } + + // Walk each SCC `A` and `B` such that `A: B` + // and ensure that universe(A) can see universe(B). + // + // This serves to enforce the 'empty/placeholder' hierarchy + // (described in more detail on `RegionKind`): + // + // ``` + // static -----+ + // | | + // empty(U0) placeholder(U1) + // | / + // empty(U1) + // ``` + // + // In particular, imagine we have variables R0 in U0 and R1 + // created in U1, and constraints like this; + // + // ``` + // R1: !1 // R1 outlives the placeholder in U1 + // R1: R0 // R1 outlives R0 + // ``` + // + // Here, we wish for R1 to be `'static`, because it + // cannot outlive `placeholder(U1)` and `empty(U0)` any other way. + // + // Thanks to this loop, what happens is that the `R1: R0` + // constraint lowers the universe of `R1` to `U0`, which in turn + // means that the `R1: !1` constraint will (later) cause + // `R1` to become `'static`. + for scc_a in constraints_scc.all_sccs() { + for &scc_b in constraints_scc.successors(scc_a) { + let scc_universe_a = scc_universes[scc_a]; + let scc_universe_b = scc_universes[scc_b]; + let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b); + if scc_universe_a != scc_universe_min { + scc_universes[scc_a] = scc_universe_min; + + debug!( + "compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \ + because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}", + scc_a = scc_a, + scc_b = scc_b, + scc_universe_min = scc_universe_min, + scc_universe_b = scc_universe_b + ); + } + } } debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes); @@ -1773,6 +1838,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Finds some region R such that `fr1: R` and `R` is live at `elem`. crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem); + debug!("find_sub_region_live_at: {:?} is in scc {:?}", fr1, self.constraint_sccs.scc(fr1)); + debug!( + "find_sub_region_live_at: {:?} is in universe {:?}", + fr1, + self.scc_universes[self.constraint_sccs.scc(fr1)] + ); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `elem` debug!( @@ -1794,13 +1865,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { .or_else(|| { // If we fail to find THAT, it may be that `fr1` is a // placeholder that cannot "fit" into its SCC. In that - // case, there should be some `r` where `fr1: r`, both - // `fr1` and `r` are in the same SCC, and `fr1` is a + // case, there should be some `r` where `fr1: r` and `fr1` is a // placeholder that `r` cannot name. We can blame that // edge. + // + // Remember that if `R1: R2`, then the universe of R1 + // must be able to name the universe of R2, because R2 will + // be at least `'empty(Universe(R2))`, and `R1` must be at + // larger than that. self.find_constraint_paths_between_regions(fr1, |r| { - self.constraint_sccs.scc(fr1) == self.constraint_sccs.scc(r) - && self.cannot_name_placeholder(r, fr1) + self.cannot_name_placeholder(r, fr1) }) }) .map(|(_path, r)| r) diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs new file mode 100644 index 0000000000000..d3964a7f515de --- /dev/null +++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs @@ -0,0 +1,36 @@ +// Test that the NLL solver cannot find a solution +// for `exists { forall { R2: R1 } }`. +// +// In this test, the impl should match `fn(T)` for some `T`, +// but we ask it to match `for<'a> fn(&'a ())`. Due to argument +// contravariance, this effectively requires a `T = &'b ()` where +// `forall<'a> { 'a: 'b }`. Therefore, we get an error. +// +// Note the use of `-Zno-leak-check` and `feature(nll)` here. These +// are presently required in order to skip the leak-check errors. +// +// c.f. Issue #57642. +// +// compile-flags:-Zno-leak-check + +#![feature(nll)] + +trait Y { + type F; + fn make_f() -> Self::F; +} + +impl Y for fn(T) { + type F = fn(T); + + fn make_f() -> Self::F { + |_| {} + } +} + +fn main() { + let _x = ::make_f(); + //~^ higher-ranked subtype error + //~| higher-ranked subtype error + //~| higher-ranked subtype error +} diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr new file mode 100644 index 0000000000000..70fb877d71689 --- /dev/null +++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr @@ -0,0 +1,20 @@ +error: higher-ranked subtype error + --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14 + | +LL | let _x = ::make_f(); + | ^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14 + | +LL | let _x = ::make_f(); + | ^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14 + | +LL | let _x = ::make_f(); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/nll/type-check-pointer-comparisons.rs b/src/test/ui/nll/type-check-pointer-comparisons.rs index 3c900356fab3b..298a6ef7ab3c5 100644 --- a/src/test/ui/nll/type-check-pointer-comparisons.rs +++ b/src/test/ui/nll/type-check-pointer-comparisons.rs @@ -21,13 +21,13 @@ fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) { } fn compare_hr_fn_ptr<'a>(f: fn(&'a i32), g: fn(&i32)) { - // Ideally this should compile with the operands swapped as well, but HIR - // type checking prevents it (and stops compilation) for now. - f == g; // OK + f == g; + //~^ ERROR higher-ranked subtype error } fn compare_const_fn_ptr<'a>(f: *const fn(&'a i32), g: *const fn(&i32)) { - f == g; // OK + f == g; + //~^ ERROR higher-ranked subtype error } fn main() {} diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr index f350b861eb6d2..0fc7480260fdb 100644 --- a/src/test/ui/nll/type-check-pointer-comparisons.stderr +++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr @@ -76,5 +76,17 @@ LL | f == g; help: `'a` and `'b` must be the same: replace one with the other -error: aborting due to 6 previous errors +error: higher-ranked subtype error + --> $DIR/type-check-pointer-comparisons.rs:24:5 + | +LL | f == g; + | ^^^^^^ + +error: higher-ranked subtype error + --> $DIR/type-check-pointer-comparisons.rs:29:5 + | +LL | f == g; + | ^^^^^^ + +error: aborting due to 8 previous errors From b8caef423d8aaef7afe228c75cb5228431e459f9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Apr 2020 10:55:27 +0000 Subject: [PATCH 2/5] reserve variable for empty root region --- src/librustc_infer/infer/mod.rs | 4 + .../borrow_check/region_infer/mod.rs | 18 ++- .../type_check/constraint_conversion.rs | 8 - .../borrow_check/universal_regions.rs | 19 ++- .../rustc.use_x.nll.0.mir | 27 ++-- .../mir-opt/nll/region-subtyping-basic.rs | 4 +- .../64bit/rustc.main.nll.0.mir | 143 +++++++++--------- .../storage_ranges/rustc.main.nll.0.mir | 11 +- .../ret-impl-trait-no-fg.stderr | 4 +- .../ui/hrtb/due-to-where-clause.nll.stderr | 2 +- .../ordinary-bounds-unrelated.nll.stderr | 2 +- .../ordinary-bounds-unsuited.nll.stderr | 2 +- src/test/ui/nll/issue-68550.rs | 15 ++ src/test/ui/nll/issue-68550.stderr | 16 ++ 14 files changed, 164 insertions(+), 111 deletions(-) create mode 100644 src/test/ui/nll/issue-68550.rs create mode 100644 src/test/ui/nll/issue-68550.stderr diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index edaa7a04b34d0..497001d009fe3 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -472,6 +472,9 @@ pub enum NLLRegionVariableOrigin { /// from a `for<'a> T` binder). Meant to represent "any region". Placeholder(ty::PlaceholderRegion), + /// The variable we create to represent `'empty(U0)`. + RootEmptyRegion, + Existential { /// If this is true, then this variable was created to represent a lifetime /// bound in a `for` binder. For example, it might have been created to @@ -493,6 +496,7 @@ impl NLLRegionVariableOrigin { NLLRegionVariableOrigin::FreeRegion => true, NLLRegionVariableOrigin::Placeholder(..) => true, NLLRegionVariableOrigin::Existential { .. } => false, + NLLRegionVariableOrigin::RootEmptyRegion => false, } } diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 9533d61b7e83e..6e0b368b61a0e 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -481,7 +481,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - NLLRegionVariableOrigin::Existential { .. } => { + NLLRegionVariableOrigin::RootEmptyRegion + | NLLRegionVariableOrigin::Existential { .. } => { // For existential, regions, nothing to do. } } @@ -1323,7 +1324,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_bound_universal_region(fr, placeholder, errors_buffer); } - NLLRegionVariableOrigin::Existential { .. } => { + NLLRegionVariableOrigin::RootEmptyRegion + | NLLRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1425,7 +1427,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_bound_universal_region(fr, placeholder, errors_buffer); } - NLLRegionVariableOrigin::Existential { .. } => { + NLLRegionVariableOrigin::RootEmptyRegion + | NLLRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1698,9 +1701,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe1.cannot_name(placeholder.universe) } - NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { .. } => { - false - } + NLLRegionVariableOrigin::RootEmptyRegion + | NLLRegionVariableOrigin::FreeRegion + | NLLRegionVariableOrigin::Existential { .. } => false, } } @@ -2019,7 +2022,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { let blame_source = match from_region_origin { NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { from_forall: false } => true, - NLLRegionVariableOrigin::Placeholder(_) + NLLRegionVariableOrigin::RootEmptyRegion + | NLLRegionVariableOrigin::Placeholder(_) | NLLRegionVariableOrigin::Existential { from_forall: true } => false, }; diff --git a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs index 8e4f44e8195a8..711271a63fbff 100644 --- a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs @@ -160,10 +160,6 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) { - // FIXME -- this is not the fix I would prefer - if let ty::ReEmpty(ty::UniverseIndex::ROOT) = a { - return; - } let b = self.to_region_vid(b); let a = self.to_region_vid(a); self.add_outlives(b, a); @@ -176,10 +172,6 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, bound: VerifyBound<'tcx>, ) { - // FIXME: I'd prefer if NLL had a notion of empty - if let ty::ReEmpty(ty::UniverseIndex::ROOT) = a { - return; - } let type_test = self.verify_to_type_test(kind, a, bound); self.add_type_test(type_test); } diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs index 4d67d7204ca6e..eb1141739a386 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/src/librustc_mir/borrow_check/universal_regions.rs @@ -54,6 +54,13 @@ pub struct UniversalRegions<'tcx> { /// The total number of universal region variables instantiated. num_universals: usize, + /// A special region variable created for the `'empty(U0)` region. + /// Note that this is **not** a "universal" region, as it doesn't + /// represent a universally bound placeholder or any such thing. + /// But we do create it here in this type because it's a useful region + /// to have around in a few limited cases. + pub root_empty: RegionVid, + /// The "defining" type for this function, with all universal /// regions instantiated. For a closure or generator, this is the /// closure type, but for a top-level function it's the `FnDef`. @@ -316,7 +323,11 @@ impl<'tcx> UniversalRegions<'tcx> { /// See `UniversalRegionIndices::to_region_vid`. pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - self.indices.to_region_vid(r) + if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r { + self.root_empty + } else { + self.indices.to_region_vid(r) + } } /// As part of the NLL unit tests, you can annotate a function with @@ -472,10 +483,16 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { _ => None, }; + let root_empty = self + .infcx + .next_nll_region_var(NLLRegionVariableOrigin::RootEmptyRegion) + .to_region_vid(); + UniversalRegions { indices, fr_static, fr_fn_body, + root_empty, first_extern_index, first_local_index, num_universals, diff --git a/src/test/mir-opt/nll/named-lifetimes-basic/rustc.use_x.nll.0.mir b/src/test/mir-opt/nll/named-lifetimes-basic/rustc.use_x.nll.0.mir index a486af608ef79..dcfb069b84aad 100644 --- a/src/test/mir-opt/nll/named-lifetimes-basic/rustc.use_x.nll.0.mir +++ b/src/test/mir-opt/nll/named-lifetimes-basic/rustc.use_x.nll.0.mir @@ -13,10 +13,11 @@ | '_#2r | U0 | {bb0[0..=1], '_#2r} | '_#3r | U0 | {bb0[0..=1], '_#3r} | '_#4r | U0 | {bb0[0..=1], '_#4r} -| '_#5r | U0 | {bb0[0..=1], '_#1r} -| '_#6r | U0 | {bb0[0..=1], '_#2r} -| '_#7r | U0 | {bb0[0..=1], '_#1r} -| '_#8r | U0 | {bb0[0..=1], '_#3r} +| '_#5r | U0 | {} +| '_#6r | U0 | {bb0[0..=1], '_#1r} +| '_#7r | U0 | {bb0[0..=1], '_#2r} +| '_#8r | U0 | {bb0[0..=1], '_#1r} +| '_#9r | U0 | {bb0[0..=1], '_#3r} | | Inference Constraints | '_#0r live at {bb0[0..=1]} @@ -24,16 +25,16 @@ | '_#2r live at {bb0[0..=1]} | '_#3r live at {bb0[0..=1]} | '_#4r live at {bb0[0..=1]} -| '_#1r: '_#5r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) -| '_#1r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) -| '_#2r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) -| '_#3r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) -| '_#5r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) -| '_#6r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) -| '_#7r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) -| '_#8r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) +| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) +| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) +| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) +| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) +| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) +| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) +| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) +| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) | -fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool { +fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool { debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27 debug x => _2; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:42: 12:43 debug y => _3; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:54: 12:55 diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index 740cb1c5e969a..66d7cda2b85a0 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -7,7 +7,9 @@ #![allow(warnings)] -fn use_x(_: usize) -> bool { true } +fn use_x(_: usize) -> bool { + true +} // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir b/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir index 4a285d035be53..61db4dba58627 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir +++ b/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir @@ -7,164 +7,165 @@ | Inferred Region Values | '_#0r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#0r, '_#1r} | '_#1r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#1r} -| '_#2r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]} -| '_#3r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]} -| '_#4r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]} +| '_#2r | U0 | {} +| '_#3r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]} +| '_#4r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]} +| '_#5r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]} | | Inference Constraints | '_#0r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]} | '_#1r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]} -| '_#2r live at {bb2[0]} -| '_#3r live at {bb2[1..=3]} -| '_#4r live at {bb2[4..=8], bb3[0], bb5[0..=2]} -| '_#2r: '_#3r due to Assignment at Single(bb2[0]) -| '_#3r: '_#4r due to Assignment at Single(bb2[3]) +| '_#3r live at {bb2[0]} +| '_#4r live at {bb2[1..=3]} +| '_#5r live at {bb2[4..=8], bb3[0], bb5[0..=2]} +| '_#3r: '_#4r due to Assignment at Single(bb2[0]) +| '_#4r: '_#5r due to Assignment at Single(bb2[3]) | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:14:11: 14:11 - let mut _1: [usize; Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:16:16: 16:17 - let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:8: 18:12 - let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:19:9: 19:18 - let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:19:15: 19:17 - let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11 + let mut _1: [usize; Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:23:9: 23:18 scope 1 { - debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - let _2: &'_#3r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:16:9: 16:10 + debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _2: &'_#4r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 scope 2 { - debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:16:9: 16:10 - let _6: &'_#4r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:17:9: 17:10 + debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + let _6: &'_#5r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 scope 3 { - debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:17:9: 17:10 + debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:10 } } } bb0: { - StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - _1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:15:17: 15:26 + StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + _1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26 // ty::Const // + ty: usize // + val: Value(Scalar(0x0000000000000001)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:15:18: 15:19 + // + span: $DIR/region-subtyping-basic.rs:17:18: 17:19 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } // ty::Const // + ty: usize // + val: Value(Scalar(0x0000000000000002)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:15:21: 15:22 + // + span: $DIR/region-subtyping-basic.rs:17:21: 17:22 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } // ty::Const // + ty: usize // + val: Value(Scalar(0x0000000000000003)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:15:24: 15:25 + // + span: $DIR/region-subtyping-basic.rs:17:24: 17:25 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) } - FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:16:9: 16:10 - StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:16:16: 16:17 - _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:16:16: 16:17 + FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 // ty::Const // + ty: usize // + val: Value(Scalar(0x0000000000000000)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:16:16: 16:17 + // + span: $DIR/region-subtyping-basic.rs:18:16: 18:17 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } - _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 + _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1 (cleanup): { - resume; // bb1[0]: scope 0 at $DIR/region-subtyping-basic.rs:14:1: 23:2 + resume; // bb1[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2 } bb2: { - _2 = &'_#2r _1[_3]; // bb2[0]: scope 1 at $DIR/region-subtyping-basic.rs:16:13: 16:18 - FakeRead(ForLet, _2); // bb2[1]: scope 1 at $DIR/region-subtyping-basic.rs:16:9: 16:10 - StorageLive(_6); // bb2[2]: scope 2 at $DIR/region-subtyping-basic.rs:17:9: 17:10 - _6 = _2; // bb2[3]: scope 2 at $DIR/region-subtyping-basic.rs:17:13: 17:14 - FakeRead(ForLet, _6); // bb2[4]: scope 2 at $DIR/region-subtyping-basic.rs:17:9: 17:10 - StorageLive(_7); // bb2[5]: scope 3 at $DIR/region-subtyping-basic.rs:18:8: 18:12 - _7 = const Const(Value(Scalar(0x01)): bool); // bb2[6]: scope 3 at $DIR/region-subtyping-basic.rs:18:8: 18:12 + _2 = &'_#3r _1[_3]; // bb2[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18 + FakeRead(ForLet, _2); // bb2[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_6); // bb2[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + _6 = _2; // bb2[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14 + FakeRead(ForLet, _6); // bb2[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + StorageLive(_7); // bb2[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + _7 = const Const(Value(Scalar(0x01)): bool); // bb2[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 // ty::Const // + ty: bool // + val: Value(Scalar(0x01)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:18:8: 18:12 + // + span: $DIR/region-subtyping-basic.rs:20:8: 20:12 // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } - FakeRead(ForMatchedPlace, _7); // bb2[7]: scope 3 at $DIR/region-subtyping-basic.rs:18:8: 18:12 - switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb3]; // bb2[8]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + FakeRead(ForMatchedPlace, _7); // bb2[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb3]; // bb2[8]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb3: { - falseEdges -> [real: bb5, imaginary: bb4]; // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + falseEdges -> [real: bb5, imaginary: bb4]; // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb4: { - StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 - _10 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 + _10 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // ty::Const // + ty: fn(usize) -> bool {use_x} // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 + // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } // ty::Const // + ty: usize // + val: Value(Scalar(0x0000000000000016)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:21:15: 21:17 + // + span: $DIR/region-subtyping-basic.rs:23:15: 23:17 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000016)) } } bb5: { - StorageLive(_8); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:18 - StorageLive(_9); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:19:15: 19:17 - _9 = (*_6); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:19:15: 19:17 - _8 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:18 + StorageLive(_8); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + StorageLive(_9); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _9 = (*_6); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _8 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // ty::Const // + ty: fn(usize) -> bool {use_x} // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:19:9: 19:14 + // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } } bb6: { - StorageDead(_9); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:19:17: 19:18 - StorageDead(_8); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:19:18: 19:19 - _0 = const Const(Value(Scalar()): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:18:13: 20:6 + StorageDead(_9); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 + StorageDead(_8); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 + _0 = const Const(Value(Scalar()): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:18:13: 20:6 + // + span: $DIR/region-subtyping-basic.rs:20:13: 22:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb8; // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + goto -> bb8; // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb7: { - StorageDead(_10); // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 - _0 = const Const(Value(Scalar()): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:20:12: 22:6 + StorageDead(_10); // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 + _0 = const Const(Value(Scalar()): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:20:12: 22:6 + // + span: $DIR/region-subtyping-basic.rs:22:12: 24:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb8; // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + goto -> bb8; // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb8: { - StorageDead(_6); // bb8[0]: scope 2 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_3); // bb8[1]: scope 1 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_2); // bb8[2]: scope 1 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_1); // bb8[3]: scope 0 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_7); // bb8[4]: scope 0 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - return; // bb8[5]: scope 0 at $DIR/region-subtyping-basic.rs:23:2: 23:2 + StorageDead(_6); // bb8[0]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_3); // bb8[1]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_2); // bb8[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_1); // bb8[3]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_7); // bb8[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + return; // bb8[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2 } } diff --git a/src/test/mir-opt/storage_ranges/rustc.main.nll.0.mir b/src/test/mir-opt/storage_ranges/rustc.main.nll.0.mir index e455a27642d36..e66ca0b135516 100644 --- a/src/test/mir-opt/storage_ranges/rustc.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges/rustc.main.nll.0.mir @@ -7,15 +7,16 @@ | Inferred Region Values | '_#0r | U0 | {bb0[0..=22], '_#0r, '_#1r} | '_#1r | U0 | {bb0[0..=22], '_#1r} -| '_#2r | U0 | {bb0[10..=11]} -| '_#3r | U0 | {bb0[11]} +| '_#2r | U0 | {} +| '_#3r | U0 | {bb0[10..=11]} +| '_#4r | U0 | {bb0[11]} | | Inference Constraints | '_#0r live at {bb0[0..=22]} | '_#1r live at {bb0[0..=22]} -| '_#2r live at {bb0[10]} -| '_#3r live at {bb0[11]} -| '_#2r: '_#3r due to Assignment at Single(bb0[10]) +| '_#3r live at {bb0[10]} +| '_#4r live at {bb0[11]} +| '_#3r: '_#4r due to Assignment at Single(bb0[10]) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11 diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr index c69595a3f4d01..da584e8ad4e0d 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr @@ -34,7 +34,7 @@ LL | | (a, b) LL | | } | |_^ | - = note: hidden type `(&u8, &u8)` captures lifetime '_#4r + = note: hidden type `(&u8, &u8)` captures lifetime '_#5r error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ret-impl-trait-no-fg.rs:9:1 @@ -48,7 +48,7 @@ LL | | (a, b) LL | | } | |_^ | - = note: hidden type `(&u8, &u8)` captures lifetime '_#5r + = note: hidden type `(&u8, &u8)` captures lifetime '_#6r error: aborting due to 5 previous errors diff --git a/src/test/ui/hrtb/due-to-where-clause.nll.stderr b/src/test/ui/hrtb/due-to-where-clause.nll.stderr index e476047a7a644..90803a0adb01b 100644 --- a/src/test/ui/hrtb/due-to-where-clause.nll.stderr +++ b/src/test/ui/hrtb/due-to-where-clause.nll.stderr @@ -2,7 +2,7 @@ error: higher-ranked subtype error --> $DIR/due-to-where-clause.rs:2:5 | LL | test::(&mut 42); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr index 5bfc446f6a573..129af80ce4a62 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ | - = note: hidden type `Ordinary<'_>` captures lifetime '_#8r + = note: hidden type `Ordinary<'_>` captures lifetime '_#9r error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr index 7291eee7b9e88..de6d5edcae511 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ | - = note: hidden type `Ordinary<'_>` captures lifetime '_#5r + = note: hidden type `Ordinary<'_>` captures lifetime '_#6r error: aborting due to previous error diff --git a/src/test/ui/nll/issue-68550.rs b/src/test/ui/nll/issue-68550.rs new file mode 100644 index 0000000000000..6bfd18de18c6a --- /dev/null +++ b/src/test/ui/nll/issue-68550.rs @@ -0,0 +1,15 @@ +// Regression test for issue #68550. +// +// The `&'static A:` where clause was triggering +// ICEs because it wound up being compiled to reference +// the `'empty(U0)` region. + +fn run<'a, A>(x: A) +where + A: 'static, + &'static A: , +{ + let _: &'a A = &x; //~ ERROR `x` does not live long enough +} + +fn main() {} diff --git a/src/test/ui/nll/issue-68550.stderr b/src/test/ui/nll/issue-68550.stderr new file mode 100644 index 0000000000000..e234ebb04e16a --- /dev/null +++ b/src/test/ui/nll/issue-68550.stderr @@ -0,0 +1,16 @@ +error[E0597]: `x` does not live long enough + --> $DIR/issue-68550.rs:12:20 + | +LL | fn run<'a, A>(x: A) + | -- lifetime `'a` defined here +... +LL | let _: &'a A = &x; + | ----- ^^ borrowed value does not live long enough + | | + | type annotation requires that `x` is borrowed for `'a` +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 074972150f5bf88152349279cb17f161c2f05988 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Apr 2020 09:59:06 +0000 Subject: [PATCH 3/5] compute SCCs in dependency order --- .../borrow_check/region_infer/mod.rs | 93 ++++++++++++------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 6e0b368b61a0e..880edf706a5d4 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -67,6 +67,12 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: Rc>, + /// SCCs in "dependency order" (or "post order"), meaning that if S1 -> S2, + /// then S2 appears first. If you process the SCCs in this order, then you + /// are always ensured that when you proces a given SCC, all of its + /// successors have been processed. + scc_dependency_order: Vec, + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if /// `B: A`. This is used to compute the universal regions that are required /// to outlive a given SCC. Computed lazily. @@ -277,7 +283,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_values.merge_liveness(scc, region, &liveness_constraints); } - let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions); + let scc_dependency_order = Self::compute_scc_dependency_order(&constraint_sccs); + + let scc_universes = + Self::compute_scc_universes(&constraint_sccs, &scc_dependency_order, &definitions); let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); @@ -290,6 +299,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, + scc_dependency_order, rev_scc_graph: None, member_constraints, member_constraints_applied: Vec::new(), @@ -307,6 +317,43 @@ impl<'tcx> RegionInferenceContext<'tcx> { result } + /// Returns a vector of all scc-ids in "dependency" or "post order". See the + /// `scc_dependency_order` field for more details. + fn compute_scc_dependency_order( + constraints_scc: &Sccs, + ) -> Vec { + let mut visited = &mut BitSet::new_empty(constraints_scc.num_sccs()); + let mut output = vec![]; + + for scc in constraints_scc.all_sccs() { + Self::compute_scc_dependency_order_if_new( + constraints_scc, + scc, + &mut visited, + &mut output, + ); + } + + output + } + + fn compute_scc_dependency_order_if_new( + constraints_scc: &Sccs, + index: ConstraintSccIndex, + visited: &mut BitSet, + output: &mut Vec, + ) { + if !visited.insert(index) { + return; + } + + for &succ in constraints_scc.successors(index) { + Self::compute_scc_dependency_order_if_new(constraints_scc, succ, visited, output); + } + + output.push(index); + } + /// Each SCC is the combination of many region variables which /// have been equated. Therefore, we can associate a universe with /// each SCC which is minimum of all the universes of its @@ -315,10 +362,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// SCC could have as well. This implies that the SCC must have /// the minimum, or narrowest, universe. fn compute_scc_universes( - constraints_scc: &Sccs, + constraint_sccs: &Sccs, + scc_dependency_order: &[ConstraintSccIndex], definitions: &IndexVec>, ) -> IndexVec { - let num_sccs = constraints_scc.num_sccs(); + let num_sccs = constraint_sccs.num_sccs(); let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs); debug!("compute_scc_universes()"); @@ -327,7 +375,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // that contains R is "no bigger" than U. This effectively sets the universe // for each SCC to be the minimum of the regions within. for (region_vid, region_definition) in definitions.iter_enumerated() { - let scc = constraints_scc.scc(region_vid); + let scc = constraint_sccs.scc(region_vid); let scc_universe = &mut scc_universes[scc]; let scc_min = std::cmp::min(region_definition.universe, *scc_universe); if scc_min != *scc_universe { @@ -372,8 +420,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraint lowers the universe of `R1` to `U0`, which in turn // means that the `R1: !1` constraint will (later) cause // `R1` to become `'static`. - for scc_a in constraints_scc.all_sccs() { - for &scc_b in constraints_scc.successors(scc_a) { + for &scc_a in scc_dependency_order { + for &scc_b in constraint_sccs.successors(scc_a) { let scc_universe_a = scc_universes[scc_a]; let scc_universe_b = scc_universes[scc_b]; let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b); @@ -616,9 +664,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // SCC. For each SCC, we visit its successors and compute // their values, then we union all those values to get our // own. - let visited = &mut BitSet::new_empty(self.constraint_sccs.num_sccs()); - for scc_index in self.constraint_sccs.all_sccs() { - self.propagate_constraint_sccs_if_new(scc_index, visited); + for i in 0..self.scc_dependency_order.len() { + self.compute_value_for_scc(self.scc_dependency_order[i]); } // Sort the applied member constraints so we can binary search @@ -626,37 +673,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc); } - /// Computes the value of the SCC `scc_a` if it has not already - /// been computed. The `visited` parameter is a bitset - #[inline] - fn propagate_constraint_sccs_if_new( - &mut self, - scc_a: ConstraintSccIndex, - visited: &mut BitSet, - ) { - if visited.insert(scc_a) { - self.propagate_constraint_sccs_new(scc_a, visited); - } - } - /// Computes the value of the SCC `scc_a`, which has not yet been - /// computed. This works by first computing all successors of the - /// SCC (if they haven't been computed already) and then unioning - /// together their elements. - fn propagate_constraint_sccs_new( - &mut self, - scc_a: ConstraintSccIndex, - visited: &mut BitSet, - ) { + /// computed, by unioning the values of its successors. + /// Assumes that all successors have been computed already + /// (which is assured by iterating over SCCs in dependency order). + fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { let constraint_sccs = self.constraint_sccs.clone(); // Walk each SCC `B` such that `A: B`... for &scc_b in constraint_sccs.successors(scc_a) { debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b); - // ...compute the value of `B`... - self.propagate_constraint_sccs_if_new(scc_b, visited); - // ...and add elements from `B` into `A`. One complication // arises because of universes: If `B` contains something // that `A` cannot name, then `A` can only contain `B` if From c7526fec8ae3bbab08e7c4a59f9b4c9e627fbdda Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Apr 2020 08:40:07 +0000 Subject: [PATCH 4/5] update ref test --- .../32bit/rustc.main.nll.0.mir | 143 +++++++++--------- 1 file changed, 72 insertions(+), 71 deletions(-) diff --git a/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir b/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir index 7d396c3f1fbd3..3e0867d9b09d9 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir +++ b/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir @@ -7,164 +7,165 @@ | Inferred Region Values | '_#0r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#0r, '_#1r} | '_#1r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#1r} -| '_#2r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]} -| '_#3r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]} -| '_#4r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]} +| '_#2r | U0 | {} +| '_#3r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]} +| '_#4r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]} +| '_#5r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]} | | Inference Constraints | '_#0r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]} | '_#1r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]} -| '_#2r live at {bb2[0]} -| '_#3r live at {bb2[1..=3]} -| '_#4r live at {bb2[4..=8], bb3[0], bb5[0..=2]} -| '_#2r: '_#3r due to Assignment at Single(bb2[0]) -| '_#3r: '_#4r due to Assignment at Single(bb2[3]) +| '_#3r live at {bb2[0]} +| '_#4r live at {bb2[1..=3]} +| '_#5r live at {bb2[4..=8], bb3[0], bb5[0..=2]} +| '_#3r: '_#4r due to Assignment at Single(bb2[0]) +| '_#4r: '_#5r due to Assignment at Single(bb2[3]) | fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:14:11: 14:11 - let mut _1: [usize; Const { ty: usize, val: Value(Scalar(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:16:16: 16:17 - let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:8: 18:12 - let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:19:9: 19:18 - let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:19:15: 19:17 - let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11 + let mut _1: [usize; Const { ty: usize, val: Value(Scalar(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:23:9: 23:18 scope 1 { - debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - let _2: &'_#3r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:16:9: 16:10 + debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + let _2: &'_#4r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 scope 2 { - debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:16:9: 16:10 - let _6: &'_#4r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:17:9: 17:10 + debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + let _6: &'_#5r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 scope 3 { - debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:17:9: 17:10 + debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:10 } } } bb0: { - StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - _1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:15:17: 15:26 + StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + _1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26 // ty::Const // + ty: usize // + val: Value(Scalar(0x00000001)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:15:18: 15:19 + // + span: $DIR/region-subtyping-basic.rs:17:18: 17:19 // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } // ty::Const // + ty: usize // + val: Value(Scalar(0x00000002)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:15:21: 15:22 + // + span: $DIR/region-subtyping-basic.rs:17:21: 17:22 // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } // ty::Const // + ty: usize // + val: Value(Scalar(0x00000003)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:15:24: 15:25 + // + span: $DIR/region-subtyping-basic.rs:17:24: 17:25 // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) } - FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:15:9: 15:14 - StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:16:9: 16:10 - StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:16:16: 16:17 - _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:16:16: 16:17 + FakeRead(ForLet, _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14 + StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 + _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 // ty::Const // + ty: usize // + val: Value(Scalar(0x00000000)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:16:16: 16:17 + // + span: $DIR/region-subtyping-basic.rs:18:16: 18:17 // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } - _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 + _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1 (cleanup): { - resume; // bb1[0]: scope 0 at $DIR/region-subtyping-basic.rs:14:1: 23:2 + resume; // bb1[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2 } bb2: { - _2 = &'_#2r _1[_3]; // bb2[0]: scope 1 at $DIR/region-subtyping-basic.rs:16:13: 16:18 - FakeRead(ForLet, _2); // bb2[1]: scope 1 at $DIR/region-subtyping-basic.rs:16:9: 16:10 - StorageLive(_6); // bb2[2]: scope 2 at $DIR/region-subtyping-basic.rs:17:9: 17:10 - _6 = _2; // bb2[3]: scope 2 at $DIR/region-subtyping-basic.rs:17:13: 17:14 - FakeRead(ForLet, _6); // bb2[4]: scope 2 at $DIR/region-subtyping-basic.rs:17:9: 17:10 - StorageLive(_7); // bb2[5]: scope 3 at $DIR/region-subtyping-basic.rs:18:8: 18:12 - _7 = const Const(Value(Scalar(0x01)): bool); // bb2[6]: scope 3 at $DIR/region-subtyping-basic.rs:18:8: 18:12 + _2 = &'_#3r _1[_3]; // bb2[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18 + FakeRead(ForLet, _2); // bb2[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10 + StorageLive(_6); // bb2[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + _6 = _2; // bb2[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14 + FakeRead(ForLet, _6); // bb2[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10 + StorageLive(_7); // bb2[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + _7 = const Const(Value(Scalar(0x01)): bool); // bb2[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 // ty::Const // + ty: bool // + val: Value(Scalar(0x01)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:18:8: 18:12 + // + span: $DIR/region-subtyping-basic.rs:20:8: 20:12 // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } - FakeRead(ForMatchedPlace, _7); // bb2[7]: scope 3 at $DIR/region-subtyping-basic.rs:18:8: 18:12 - switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb3]; // bb2[8]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + FakeRead(ForMatchedPlace, _7); // bb2[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12 + switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb3]; // bb2[8]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb3: { - falseEdges -> [real: bb5, imaginary: bb4]; // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + falseEdges -> [real: bb5, imaginary: bb4]; // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb4: { - StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 - _10 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 + _10 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // ty::Const // + ty: fn(usize) -> bool {use_x} // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 + // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } // ty::Const // + ty: usize // + val: Value(Scalar(0x00000016)) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:21:15: 21:17 + // + span: $DIR/region-subtyping-basic.rs:23:15: 23:17 // + literal: Const { ty: usize, val: Value(Scalar(0x00000016)) } } bb5: { - StorageLive(_8); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:18 - StorageLive(_9); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:19:15: 19:17 - _9 = (*_6); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:19:15: 19:17 - _8 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:19:9: 19:18 + StorageLive(_8); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + StorageLive(_9); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _9 = (*_6); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 + _8 = const Const(Value(Scalar()): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // ty::Const // + ty: fn(usize) -> bool {use_x} // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:19:9: 19:14 + // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar()) } } bb6: { - StorageDead(_9); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:19:17: 19:18 - StorageDead(_8); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:19:18: 19:19 - _0 = const Const(Value(Scalar()): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:18:13: 20:6 + StorageDead(_9); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 + StorageDead(_8); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 + _0 = const Const(Value(Scalar()): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:18:13: 20:6 + // + span: $DIR/region-subtyping-basic.rs:20:13: 22:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb8; // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + goto -> bb8; // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb7: { - StorageDead(_10); // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 - _0 = const Const(Value(Scalar()): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:20:12: 22:6 + StorageDead(_10); // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 + _0 = const Const(Value(Scalar()): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/region-subtyping-basic.rs:20:12: 22:6 + // + span: $DIR/region-subtyping-basic.rs:22:12: 24:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb8; // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:18:5: 22:6 + goto -> bb8; // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb8: { - StorageDead(_6); // bb8[0]: scope 2 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_3); // bb8[1]: scope 1 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_2); // bb8[2]: scope 1 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_1); // bb8[3]: scope 0 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - StorageDead(_7); // bb8[4]: scope 0 at $DIR/region-subtyping-basic.rs:23:1: 23:2 - return; // bb8[5]: scope 0 at $DIR/region-subtyping-basic.rs:23:2: 23:2 + StorageDead(_6); // bb8[0]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_3); // bb8[1]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_2); // bb8[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_1); // bb8[3]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + StorageDead(_7); // bb8[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2 + return; // bb8[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2 } } From cb9458d3ff7f64c309bc80776d71e4f73705f4ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Apr 2020 08:52:29 +0000 Subject: [PATCH 5/5] sccs are computed in dependency order We don't need the `scc_dependency_order` vector, `all_sccs` is already in dependency order. --- src/librustc_data_structures/graph/scc/mod.rs | 5 ++ .../borrow_check/region_infer/mod.rs | 58 ++----------------- 2 files changed, 10 insertions(+), 53 deletions(-) diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 7ecf3e3cb8d5d..57eaf56f268f8 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -47,6 +47,11 @@ impl Sccs { } /// Returns an iterator over the SCCs in the graph. + /// + /// The SCCs will be iterated in **dependency order** (or **post order**), + /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after. + /// This is convenient when the edges represent dependencies: when you visit + /// `S1`, the value for `S2` will already have been computed. pub fn all_sccs(&self) -> impl Iterator { (0..self.scc_data.len()).map(S::new) } diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 880edf706a5d4..09eb1bb2fc482 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -6,7 +6,6 @@ use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_hir::def_id::DefId; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::QueryOutlivesConstraint; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; @@ -67,12 +66,6 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: Rc>, - /// SCCs in "dependency order" (or "post order"), meaning that if S1 -> S2, - /// then S2 appears first. If you process the SCCs in this order, then you - /// are always ensured that when you proces a given SCC, all of its - /// successors have been processed. - scc_dependency_order: Vec, - /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if /// `B: A`. This is used to compute the universal regions that are required /// to outlive a given SCC. Computed lazily. @@ -283,10 +276,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_values.merge_liveness(scc, region, &liveness_constraints); } - let scc_dependency_order = Self::compute_scc_dependency_order(&constraint_sccs); - - let scc_universes = - Self::compute_scc_universes(&constraint_sccs, &scc_dependency_order, &definitions); + let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions); let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions); @@ -299,7 +289,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, - scc_dependency_order, rev_scc_graph: None, member_constraints, member_constraints_applied: Vec::new(), @@ -317,43 +306,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { result } - /// Returns a vector of all scc-ids in "dependency" or "post order". See the - /// `scc_dependency_order` field for more details. - fn compute_scc_dependency_order( - constraints_scc: &Sccs, - ) -> Vec { - let mut visited = &mut BitSet::new_empty(constraints_scc.num_sccs()); - let mut output = vec![]; - - for scc in constraints_scc.all_sccs() { - Self::compute_scc_dependency_order_if_new( - constraints_scc, - scc, - &mut visited, - &mut output, - ); - } - - output - } - - fn compute_scc_dependency_order_if_new( - constraints_scc: &Sccs, - index: ConstraintSccIndex, - visited: &mut BitSet, - output: &mut Vec, - ) { - if !visited.insert(index) { - return; - } - - for &succ in constraints_scc.successors(index) { - Self::compute_scc_dependency_order_if_new(constraints_scc, succ, visited, output); - } - - output.push(index); - } - /// Each SCC is the combination of many region variables which /// have been equated. Therefore, we can associate a universe with /// each SCC which is minimum of all the universes of its @@ -363,7 +315,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// the minimum, or narrowest, universe. fn compute_scc_universes( constraint_sccs: &Sccs, - scc_dependency_order: &[ConstraintSccIndex], definitions: &IndexVec>, ) -> IndexVec { let num_sccs = constraint_sccs.num_sccs(); @@ -420,7 +371,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraint lowers the universe of `R1` to `U0`, which in turn // means that the `R1: !1` constraint will (later) cause // `R1` to become `'static`. - for &scc_a in scc_dependency_order { + for scc_a in constraint_sccs.all_sccs() { for &scc_b in constraint_sccs.successors(scc_a) { let scc_universe_a = scc_universes[scc_a]; let scc_universe_b = scc_universes[scc_b]; @@ -664,8 +615,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // SCC. For each SCC, we visit its successors and compute // their values, then we union all those values to get our // own. - for i in 0..self.scc_dependency_order.len() { - self.compute_value_for_scc(self.scc_dependency_order[i]); + let constraint_sccs = self.constraint_sccs.clone(); + for scc in constraint_sccs.all_sccs() { + self.compute_value_for_scc(scc); } // Sort the applied member constraints so we can binary search