From 771fdd99852ba8465b76674466b470a1ee3dd3c2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Apr 2020 11:23:30 +0000 Subject: [PATCH 1/9] 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/9] 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/9] 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/9] 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/9] 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 From f8f0f7b228a2587195863a62766cf6ba022447af Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 22 Apr 2020 11:57:40 -0400 Subject: [PATCH 6/9] Add help message for missing right operand in condition --- src/librustc_parse/parser/expr.rs | 5 +++++ src/test/ui/if/if-without-block.stderr | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 986f5410e26c0..85587b7733a20 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1550,6 +1550,11 @@ impl<'a> Parser<'a> { let block = self.parse_block().map_err(|mut err| { if not_block { err.span_label(lo, "this `if` expression has a condition, but no block"); + if let ExprKind::Binary(_, _, ref right) = cond.kind { + if let ExprKind::Block(_, _) = right.kind { + err.help("maybe you forgot the right operand of the condition?"); + } + } } err })?; diff --git a/src/test/ui/if/if-without-block.stderr b/src/test/ui/if/if-without-block.stderr index 34df8e3d77946..ee2bb62e2bb57 100644 --- a/src/test/ui/if/if-without-block.stderr +++ b/src/test/ui/if/if-without-block.stderr @@ -6,6 +6,8 @@ LL | if 5 == { ... LL | } | ^ expected `{` + | + = help: maybe you forgot the right operand of the condition? error: aborting due to previous error From 46154f28bd69b92e74199f476590e70336329bda Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 22 Apr 2020 15:48:30 -0700 Subject: [PATCH 7/9] Move `{Free,}RegionRelations` and `FreeRegionMap` out of `rustc_middle` --- Cargo.lock | 1 + src/librustc_infer/Cargo.toml | 1 + .../infer/free_regions.rs} | 44 ++++++++++++++++++- .../infer/lexical_region_resolve/graphviz.rs | 2 +- .../infer/lexical_region_resolve/mod.rs | 2 +- src/librustc_infer/infer/mod.rs | 3 +- src/librustc_infer/infer/outlives/env.rs | 2 +- src/librustc_middle/middle/free_region.rs | 44 ------------------- src/librustc_middle/middle/mod.rs | 1 - src/librustc_middle/ty/mod.rs | 1 - .../type_check/free_region_relations.rs | 2 +- src/librustc_trait_selection/opaque_types.rs | 2 +- 12 files changed, 52 insertions(+), 53 deletions(-) rename src/{librustc_middle/ty/free_region_map.rs => librustc_infer/infer/free_regions.rs} (74%) delete mode 100644 src/librustc_middle/middle/free_region.rs diff --git a/Cargo.lock b/Cargo.lock index 69b582cd8fbc4..f31ef938183b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3852,6 +3852,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "serialize", "smallvec 1.0.0", ] diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml index bc4080ac6c8de..fa8e5a2ab78b4 100644 --- a/src/librustc_infer/Cargo.toml +++ b/src/librustc_infer/Cargo.toml @@ -19,6 +19,7 @@ rustc_hir = { path = "../librustc_hir" } rustc_index = { path = "../librustc_index" } rustc_macros = { path = "../librustc_macros" } rustc_session = { path = "../librustc_session" } +rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_middle/ty/free_region_map.rs b/src/librustc_infer/infer/free_regions.rs similarity index 74% rename from src/librustc_middle/ty/free_region_map.rs rename to src/librustc_infer/infer/free_regions.rs index 2ab12a4acbfa4..e31c524c19710 100644 --- a/src/librustc_middle/ty/free_region_map.rs +++ b/src/librustc_infer/infer/free_regions.rs @@ -1,5 +1,47 @@ -use crate::ty::{self, Lift, Region, TyCtxt}; +//! This module handles the relationships between "free regions", i.e., lifetime parameters. +//! Ordinarily, free regions are unrelated to one another, but they can be related via implied +//! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type, +//! and use that to decide when one free region outlives another, and so forth. + use rustc_data_structures::transitive_relation::TransitiveRelation; +use rustc_hir::def_id::DefId; +use rustc_middle::middle::region; +use rustc_middle::ty::{self, Lift, Region, TyCtxt}; + +/// Combines a `region::ScopeTree` (which governs relationships between +/// scopes) and a `FreeRegionMap` (which governs relationships between +/// free regions) to yield a complete relation between concrete +/// regions. +/// +/// This stuff is a bit convoluted and should be refactored, but as we +/// transition to NLL, it'll all go away anyhow. +pub struct RegionRelations<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, + + /// The context used to fetch the region maps. + pub context: DefId, + + /// The region maps for the given context. + pub region_scope_tree: &'a region::ScopeTree, + + /// Free-region relationships. + pub free_regions: &'a FreeRegionMap<'tcx>, +} + +impl<'a, 'tcx> RegionRelations<'a, 'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + context: DefId, + region_scope_tree: &'a region::ScopeTree, + free_regions: &'a FreeRegionMap<'tcx>, + ) -> Self { + Self { tcx, context, region_scope_tree, free_regions } + } + + pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { + self.free_regions.lub_free_regions(self.tcx, r_a, r_b) + } +} #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)] pub struct FreeRegionMap<'tcx> { diff --git a/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs index 141424fc0c781..5d3e8f440d6fd 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs @@ -10,10 +10,10 @@ use graphviz as dot; use super::Constraint; use crate::infer::region_constraints::RegionConstraintData; +use crate::infer::RegionRelations; use crate::infer::SubregionOrigin; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::DefIndex; -use rustc_middle::middle::free_region::RegionRelations; use rustc_middle::middle::region; use rustc_middle::ty; diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs index c8d357749784c..3ff0e26a4dc38 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -6,6 +6,7 @@ use crate::infer::region_constraints::MemberConstraint; use crate::infer::region_constraints::RegionConstraintData; use crate::infer::region_constraints::VarInfos; use crate::infer::region_constraints::VerifyBound; +use crate::infer::RegionRelations; use crate::infer::RegionVariableOrigin; use crate::infer::RegionckMode; use crate::infer::SubregionOrigin; @@ -14,7 +15,6 @@ use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::middle::free_region::RegionRelations; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index edaa7a04b34d0..8e6a66efac4a6 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -18,7 +18,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; -use rustc_middle::middle::free_region::RegionRelations; use rustc_middle::middle::region; use rustc_middle::mir; use rustc_middle::mir::interpret::ConstEvalResult; @@ -39,6 +38,7 @@ use std::collections::BTreeMap; use std::fmt; use self::combine::CombineFields; +use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; @@ -50,6 +50,7 @@ pub mod canonical; mod combine; mod equate; pub mod error_reporting; +pub mod free_regions; mod freshen; mod fudge; mod glb; diff --git a/src/librustc_infer/infer/outlives/env.rs b/src/librustc_infer/infer/outlives/env.rs index 06a23269389a7..1a9e20e79fe1e 100644 --- a/src/librustc_infer/infer/outlives/env.rs +++ b/src/librustc_infer/infer/outlives/env.rs @@ -1,9 +1,9 @@ +use crate::infer::free_regions::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_middle::ty; -use rustc_middle::ty::free_region_map::FreeRegionMap; use super::explicit_outlives_bounds; diff --git a/src/librustc_middle/middle/free_region.rs b/src/librustc_middle/middle/free_region.rs deleted file mode 100644 index 62ccd94674488..0000000000000 --- a/src/librustc_middle/middle/free_region.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! This module handles the relationships between "free regions", i.e., lifetime parameters. -//! Ordinarily, free regions are unrelated to one another, but they can be related via implied -//! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type, -//! and use that to decide when one free region outlives another, and so forth. - -use crate::middle::region; -use crate::ty::free_region_map::FreeRegionMap; -use crate::ty::{Region, TyCtxt}; -use rustc_hir::def_id::DefId; - -/// Combines a `region::ScopeTree` (which governs relationships between -/// scopes) and a `FreeRegionMap` (which governs relationships between -/// free regions) to yield a complete relation between concrete -/// regions. -/// -/// This stuff is a bit convoluted and should be refactored, but as we -/// transition to NLL, it'll all go away anyhow. -pub struct RegionRelations<'a, 'tcx> { - pub tcx: TyCtxt<'tcx>, - - /// The context used to fetch the region maps. - pub context: DefId, - - /// The region maps for the given context. - pub region_scope_tree: &'a region::ScopeTree, - - /// Free-region relationships. - pub free_regions: &'a FreeRegionMap<'tcx>, -} - -impl<'a, 'tcx> RegionRelations<'a, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - context: DefId, - region_scope_tree: &'a region::ScopeTree, - free_regions: &'a FreeRegionMap<'tcx>, - ) -> Self { - Self { tcx, context, region_scope_tree, free_regions } - } - - pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { - self.free_regions.lub_free_regions(self.tcx, r_a, r_b) - } -} diff --git a/src/librustc_middle/middle/mod.rs b/src/librustc_middle/middle/mod.rs index 464488964afb7..9bc9ca6707afe 100644 --- a/src/librustc_middle/middle/mod.rs +++ b/src/librustc_middle/middle/mod.rs @@ -2,7 +2,6 @@ pub mod codegen_fn_attrs; pub mod cstore; pub mod dependency_format; pub mod exported_symbols; -pub mod free_region; pub mod lang_items; pub mod lib_features { use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 73e7e623b12ad..b955ce91e598d 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -96,7 +96,6 @@ pub mod error; pub mod fast_reject; pub mod flags; pub mod fold; -pub mod free_region_map; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 0583295bfca77..f97dff146450c 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -1,12 +1,12 @@ use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::free_regions::FreeRegionRelations; use rustc_infer::infer::outlives; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty::free_region_map::FreeRegionRelations; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index f67b8b87ced5f..b464a576950b4 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -6,10 +6,10 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_hir::Node; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; +use rustc_infer::infer::free_regions::FreeRegionRelations; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; -use rustc_middle::ty::free_region_map::FreeRegionRelations; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use rustc_session::config::nightly_options; From 7ac093fda9f458ac4c9d5bd52e44d1247627a3b6 Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Sat, 25 Apr 2020 15:43:19 -0400 Subject: [PATCH 8/9] Detect git version before attempting to use --progress Otherwise each update is run twice and errors are printed --- src/bootstrap/bootstrap.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5efed61b541e..2aa3f9c7ec04b 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -2,6 +2,7 @@ import argparse import contextlib import datetime +import distutils.version import hashlib import os import re @@ -331,6 +332,7 @@ def __init__(self): self.use_locked_deps = '' self.use_vendored_sources = '' self.verbose = False + self.git_version = None def download_stage0(self): """Fetch the build system for Rust, written in Rust @@ -743,15 +745,13 @@ def update_submodule(self, module, checked_out, recorded_submodules): run(["git", "submodule", "-q", "sync", module], cwd=self.rust_root, verbose=self.verbose) - try: - run(["git", "submodule", "update", - "--init", "--recursive", "--progress", module], - cwd=self.rust_root, verbose=self.verbose, exception=True) - except RuntimeError: - # Some versions of git don't support --progress. - run(["git", "submodule", "update", - "--init", "--recursive", module], - cwd=self.rust_root, verbose=self.verbose) + + update_args = ["git", "submodule", "update", "--init", "--recursive"] + if self.git_version >= distutils.version.LooseVersion("2.11.0"): + update_args.append("--progress") + update_args.append(module) + run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True) + run(["git", "reset", "-q", "--hard"], cwd=module_path, verbose=self.verbose) run(["git", "clean", "-qdfx"], @@ -763,9 +763,13 @@ def update_submodules(self): self.get_toml('submodules') == "false": return - # check the existence of 'git' command + default_encoding = sys.getdefaultencoding() + + # check the existence and version of 'git' command try: - subprocess.check_output(['git', '--version']) + git_version_output = subprocess.check_output(['git', '--version']) + git_version_str = git_version_output.strip().split()[2].decode(default_encoding) + self.git_version = distutils.version.LooseVersion(git_version_str) except (subprocess.CalledProcessError, OSError): print("error: `git` is not found, please make sure it's installed and in the path.") sys.exit(1) From eda7f8fdff16aee5ff30b150555c479f885ba993 Mon Sep 17 00:00:00 2001 From: cohenarthur Date: Thu, 30 Apr 2020 11:00:45 +0200 Subject: [PATCH 9/9] rename-unique: Rename Unique::empty() to Unique::dangling() rename-unique: Change calls and doc in raw_vec.rs rename-unique: Change empty() -> dangling() in const-ptr-unique-rpass.rs --- src/liballoc/raw_vec.rs | 10 +++++----- src/libcore/ptr/unique.rs | 3 +-- src/test/ui/consts/const-ptr-unique-rpass.rs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index ca165b61e26a7..a8e19c9cbaa86 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -25,9 +25,9 @@ mod tests; /// involved. This type is excellent for building your own data structures like Vec and VecDeque. /// In particular: /// -/// * Produces `Unique::empty()` on zero-sized types. -/// * Produces `Unique::empty()` on zero-length allocations. -/// * Avoids freeing `Unique::empty()`. +/// * Produces `Unique::dangling()` on zero-sized types. +/// * Produces `Unique::dangling()` on zero-length allocations. +/// * Avoids freeing `Unique::dangling()`. /// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). /// * Guards against 32-bit systems allocating more than isize::MAX bytes. /// * Guards against overflowing your length. @@ -125,7 +125,7 @@ impl RawVec { /// the returned `RawVec`. pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. - Self { ptr: Unique::empty(), cap: 0, alloc } + Self { ptr: Unique::dangling(), cap: 0, alloc } } /// Like `with_capacity`, but parameterized over the choice of @@ -172,7 +172,7 @@ impl RawVec { } /// Gets a raw pointer to the start of the allocation. Note that this is - /// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must + /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. pub fn ptr(&self) -> *mut T { self.ptr.as_ptr() diff --git a/src/libcore/ptr/unique.rs b/src/libcore/ptr/unique.rs index f5a5baceacce8..f58d35f06137d 100644 --- a/src/libcore/ptr/unique.rs +++ b/src/libcore/ptr/unique.rs @@ -70,9 +70,8 @@ impl Unique { /// a `T`, which means this must not be used as a "not yet initialized" /// sentinel value. Types that lazily allocate must track initialization by /// some other means. - // FIXME: rename to dangling() to match NonNull? #[inline] - pub const fn empty() -> Self { + pub const fn dangling() -> Self { // SAFETY: mem::align_of() returns a valid, non-null pointer. The // conditions to call new_unchecked() are thus respected. unsafe { Unique::new_unchecked(mem::align_of::() as *mut T) } diff --git a/src/test/ui/consts/const-ptr-unique-rpass.rs b/src/test/ui/consts/const-ptr-unique-rpass.rs index e8735e1a32c2c..fc13bb98bd2c9 100644 --- a/src/test/ui/consts/const-ptr-unique-rpass.rs +++ b/src/test/ui/consts/const-ptr-unique-rpass.rs @@ -8,9 +8,9 @@ use test::black_box as b; // prevent promotion of the argument and const-propaga use std::ptr::Unique; -const PTR: *mut u32 = Unique::empty().as_ptr(); +const PTR: *mut u32 = Unique::dangling().as_ptr(); pub fn main() { // Be super-extra paranoid and cast the fn items to fn pointers before blackboxing them. - assert_eq!(PTR, b:: _>(Unique::::empty)().as_ptr()); + assert_eq!(PTR, b:: _>(Unique::::dangling)().as_ptr()); }