From 771fdd99852ba8465b76674466b470a1ee3dd3c2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Apr 2020 11:23:30 +0000 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 9a2bca6a52158577817f0cc1f13c1b48206bf275 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 16 Apr 2020 02:00:23 +0200 Subject: [PATCH 04/12] rustc: fix check_attr() for methods, closures and foreign functions UI tests are updated with additional error messages that were missing before. --- src/librustc_passes/check_attr.rs | 5 +- ...ture-gate-unboxed-closures-manual-impls.rs | 4 ++ ...-gate-unboxed-closures-manual-impls.stderr | 48 +++++++++++++++---- .../feature-gate-unboxed-closures.rs | 1 + .../feature-gate-unboxed-closures.stderr | 12 ++++- src/test/ui/issues/issue-3214.rs | 3 ++ src/test/ui/issues/issue-3214.stderr | 14 ++++-- src/test/ui/macros/issue-68060.rs | 2 - src/test/ui/macros/issue-68060.stderr | 6 +-- 9 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 6c9d25cfaa54b..b1b58b0e3532b 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -76,7 +76,7 @@ impl CheckAttrVisitor<'tcx> { return; } - if target == Target::Fn { + if matches!(target, Target::Fn | Target::Method(_) | Target::ForeignFn) { self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id)); } @@ -391,6 +391,9 @@ impl CheckAttrVisitor<'tcx> { ); } } + if target == Target::Closure { + self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(expr.hir_id)); + } } fn check_used(&self, attrs: &'hir [Attribute], target: Target) { diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs index ff6e2b8290389..eecf2046ccbea 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.rs @@ -8,24 +8,28 @@ struct Foo; impl Fn<()> for Foo { //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change +//~| ERROR manual implementations of `Fn` are experimental extern "rust-call" fn call(self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change } struct Foo1; impl FnOnce() for Foo1 { //~^ ERROR associated type bindings are not allowed here +//~| ERROR manual implementations of `FnOnce` are experimental extern "rust-call" fn call_once(self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change } struct Bar; impl FnMut<()> for Bar { //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change +//~| ERROR manual implementations of `FnMut` are experimental extern "rust-call" fn call_mut(&self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change } struct Baz; impl FnOnce<()> for Baz { //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change +//~| ERROR manual implementations of `FnOnce` are experimental extern "rust-call" fn call_once(&self, args: ()) -> () {} //~^ ERROR rust-call ABI is subject to change } diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 892020332d702..22a1ce3061889 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -1,5 +1,5 @@ error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:12:12 | LL | extern "rust-call" fn call(self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | extern "rust-call" fn call(self, args: ()) -> () {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:19:12 | LL | extern "rust-call" fn call_once(self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | extern "rust-call" fn call_once(self, args: ()) -> () {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:26:12 | LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:12 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:33:12 | LL | extern "rust-call" fn call_once(&self, args: ()) -> () {} | ^^^^^^^^^^^ @@ -44,13 +44,13 @@ LL | impl Fn<()> for Foo { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0229]: associated type bindings are not allowed here - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:15:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6 | LL | impl FnOnce() for Foo1 { | ^^^^^^^^ associated type not allowed here error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6 | LL | impl FnMut<()> for Bar { | ^^^^^^^^^ help: use parenthetical notation instead: `FnMut() -> ()` @@ -59,7 +59,7 @@ LL | impl FnMut<()> for Bar { = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:27:6 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6 | LL | impl FnOnce<()> for Baz { | ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()` @@ -67,7 +67,39 @@ LL | impl FnOnce<()> for Baz { = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -error: aborting due to 8 previous errors +error[E0183]: manual implementations of `Fn` are experimental + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:1 + | +LL | impl Fn<()> for Foo { + | ^^^^^^^^^^^^^^^^^^^ manual implementations of `Fn` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0183]: manual implementations of `FnMut` are experimental + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:1 + | +LL | impl FnMut<()> for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnMut` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0183]: manual implementations of `FnOnce` are experimental + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:1 + | +LL | impl FnOnce() for Foo1 { + | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0183]: manual implementations of `FnOnce` are experimental + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:1 + | +LL | impl FnOnce<()> for Baz { + | ^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error: aborting due to 12 previous errors Some errors have detailed explanations: E0229, E0658. For more information about an error, try `rustc --explain E0229`. diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs b/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs index b8d3aa4a141df..ebc5a2536f672 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs @@ -4,6 +4,7 @@ struct Test; impl FnOnce<(u32, u32)> for Test { //~^ ERROR the precise format of `Fn`-family traits' type parameters is subject to change +//~| ERROR manual implementations of `FnOnce` are experimental type Output = u32; extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr index feda2fe49f95c..2c8915d0ac334 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr @@ -1,5 +1,5 @@ error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures.rs:9:12 + --> $DIR/feature-gate-unboxed-closures.rs:10:12 | LL | extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { | ^^^^^^^^^^^ @@ -16,6 +16,14 @@ LL | impl FnOnce<(u32, u32)> for Test { = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -error: aborting due to 2 previous errors +error[E0183]: manual implementations of `FnOnce` are experimental + --> $DIR/feature-gate-unboxed-closures.rs:5:1 + | +LL | impl FnOnce<(u32, u32)> for Test { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-3214.rs b/src/test/ui/issues/issue-3214.rs index 9a727aa305797..030677c879fb5 100644 --- a/src/test/ui/issues/issue-3214.rs +++ b/src/test/ui/issues/issue-3214.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + fn foo() { struct Foo { x: T, //~ ERROR can't use generic parameters from outer function @@ -5,6 +7,7 @@ fn foo() { impl Drop for Foo { //~^ ERROR wrong number of type arguments + //~| ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates fn drop(&mut self) {} } } diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index 02c8da10bb4a3..30bc6cb115ffc 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -1,5 +1,5 @@ error[E0401]: can't use generic parameters from outer function - --> $DIR/issue-3214.rs:3:12 + --> $DIR/issue-3214.rs:5:12 | LL | fn foo() { | --- - type parameter from outer function @@ -10,12 +10,18 @@ LL | x: T, | ^ use of generic parameter from outer function error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-3214.rs:6:26 + --> $DIR/issue-3214.rs:8:26 | LL | impl Drop for Foo { | ^ unexpected type argument -error: aborting due to 2 previous errors +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-3214.rs:8:10 + | +LL | impl Drop for Foo { + | ^ unconstrained type parameter + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0401. +Some errors have detailed explanations: E0107, E0207, E0401. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index 85ebd66b66cb6..bc70f8ffec2b2 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -1,5 +1,3 @@ -// build-fail - #![feature(track_caller)] fn main() { diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index 230867410d966..3ea49e614e633 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -1,5 +1,5 @@ error: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/issue-68060.rs:8:13 + --> $DIR/issue-68060.rs:6:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions @@ -8,13 +8,13 @@ LL | |_| (), | ------ not an `unsafe` function error: the feature named `` is not valid for this target - --> $DIR/issue-68060.rs:8:30 + --> $DIR/issue-68060.rs:6:30 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^ `` is not valid for this target error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:11:13 + --> $DIR/issue-68060.rs:9:13 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ From 6c700dc11c72993d5fa5905355a69c6524e960d3 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 16 Apr 2020 17:11:05 +0200 Subject: [PATCH 05/12] Extend UI tests for fixed check_attr() Add testcases for the `#[track_caller]` and `#[target_feature(..)]` function attributes for errors that were not not caught before. --- .../error-with-invalid-abi.rs | 6 ++++++ .../error-with-invalid-abi.stderr | 8 +++++++- .../ui/target-feature/invalid-attribute.rs | 17 ++++++++++++++++ .../target-feature/invalid-attribute.stderr | 20 ++++++++++++++++++- 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs index 20d29619ba404..1145f7786c78b 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -4,4 +4,10 @@ extern "C" fn f() {} //~^^ ERROR `#[track_caller]` requires Rust ABI +extern "C" { + #[track_caller] + fn g(); + //~^^ ERROR `#[track_caller]` requires Rust ABI +} + fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr index 2a3a4385c8bf7..e08c52fabd6b7 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -4,6 +4,12 @@ error[E0737]: `#[track_caller]` requires Rust ABI LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-invalid-abi.rs:8:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0737`. diff --git a/src/test/ui/target-feature/invalid-attribute.rs b/src/test/ui/target-feature/invalid-attribute.rs index 46680336632f9..19c8c3dd4886b 100644 --- a/src/test/ui/target-feature/invalid-attribute.rs +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -65,9 +65,26 @@ trait Baz { } #[target_feature(enable = "sse2")] unsafe fn test() {} +trait Quux { + fn foo(); +} + +impl Quux for Foo { + #[target_feature(enable = "sse2")] + //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions + //~| NOTE can only be applied to `unsafe` functions + fn foo() {} + //~^ NOTE not an `unsafe` function +} + fn main() { unsafe { foo(); bar(); } + #[target_feature(enable = "sse2")] + //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions + //~| NOTE can only be applied to `unsafe` functions + || {}; + //~^ NOTE not an `unsafe` function } diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index abfe5dd219770..76273d66ac2cf 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -91,5 +91,23 @@ error: cannot use `#[inline(always)]` with `#[target_feature]` LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/invalid-attribute.rs:85:5 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions +... +LL | || {}; + | ----- not an `unsafe` function + +error: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/invalid-attribute.rs:73:5 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions +... +LL | fn foo() {} + | ----------- not an `unsafe` function + +error: aborting due to 14 previous errors From c7526fec8ae3bbab08e7c4a59f9b4c9e627fbdda Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Apr 2020 08:40:07 +0000 Subject: [PATCH 06/12] 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 07/12] 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 7ac093fda9f458ac4c9d5bd52e44d1247627a3b6 Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Sat, 25 Apr 2020 15:43:19 -0400 Subject: [PATCH 08/12] 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 5a5fa39909f0793790c9365bd6a1c81347a0f8cf Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 25 Apr 2020 19:14:58 -0400 Subject: [PATCH 09/12] Handle build completion message from Cargo This was introduced in the recent bump to 1.43 bootstrap cargo --- src/bootstrap/compile.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 06ab0a9c310af..2ad2b1a5a4106 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1012,4 +1012,7 @@ pub enum CargoMessage<'a> { BuildScriptExecuted { package_id: Cow<'a, str>, }, + BuildFinished { + success: bool, + }, } From edfca5fe9c7b6c12a9d48ea2dffd6fffff8501a4 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Mon, 27 Apr 2020 01:41:38 +0800 Subject: [PATCH 10/12] Move branch point upwards to avoid unnecessary mk_ptr() --- src/librustc_typeck/check/coercion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 3d665123f6767..c1a3ff518b338 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -771,10 +771,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::RawPtr(mt) => (false, mt), _ => return self.unify_and(a, b, identity), }; + coerce_mutbls(mt_a.mutbl, mutbl_b)?; // Check that the types which they point at are compatible. let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty }); - coerce_mutbls(mt_a.mutbl, mutbl_b)?; // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. From a9340b1f69b0a301214934cd9b24dcf348522988 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Tue, 28 Apr 2020 10:58:06 +0800 Subject: [PATCH 11/12] Rename function to `suggest_deref_ref_or_into` because it's suggesting derefence instructions --- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/expr.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c75283e419a6d..8c3a010303768 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { self.annotate_expected_due_to_let_ty(err, expr); self.suggest_compatible_variants(err, expr, expected, expr_ty); - self.suggest_ref_or_into(err, expr, expected, expr_ty); + self.suggest_deref_ref_or_into(err, expr, expected, expr_ty); if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { return; } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index d287589789e2d..92ddfbff824cd 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { let expr = expr.peel_drop_temps(); - self.suggest_ref_or_into(&mut err, expr, expected_ty, ty); + self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty); extend_err(&mut err); // Error possibly reported in `check_assign` so avoid emitting error again. err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5877c6d269ad6..adbab3d4cb620 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5029,7 +5029,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - pub fn suggest_ref_or_into( + pub fn suggest_deref_ref_or_into( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, From a9858791134253d004971664fd7e9bd9b0983723 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Wed, 29 Apr 2020 11:41:34 +0800 Subject: [PATCH 12/12] Suggest deref when coercing `ty::Ref` to `ty::RawPtr` --- src/librustc_typeck/check/coercion.rs | 6 ++-- src/librustc_typeck/check/demand.rs | 38 ++++++++++++++++++++++++- src/test/ui/issues/issue-32122-1.fixed | 17 +++++++++++ src/test/ui/issues/issue-32122-1.rs | 17 +++++++++++ src/test/ui/issues/issue-32122-1.stderr | 16 +++++++++++ src/test/ui/issues/issue-32122-2.fixed | 28 ++++++++++++++++++ src/test/ui/issues/issue-32122-2.rs | 28 ++++++++++++++++++ src/test/ui/issues/issue-32122-2.stderr | 16 +++++++++++ 8 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/issues/issue-32122-1.fixed create mode 100644 src/test/ui/issues/issue-32122-1.rs create mode 100644 src/test/ui/issues/issue-32122-1.stderr create mode 100644 src/test/ui/issues/issue-32122-2.fixed create mode 100644 src/test/ui/issues/issue-32122-2.rs create mode 100644 src/test/ui/issues/issue-32122-2.stderr diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c1a3ff518b338..5d1a1a164855d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -74,7 +74,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; -struct Coerce<'a, 'tcx> { +pub struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, @@ -124,7 +124,7 @@ fn success<'tcx>( } impl<'f, 'tcx> Coerce<'f, 'tcx> { - fn new( + pub fn new( fcx: &'f FnCtxt<'f, 'tcx>, cause: ObligationCause<'tcx>, allow_two_phase: AllowTwoPhase, @@ -132,7 +132,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Coerce { fcx, cause, allow_two_phase, use_lub: false } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + pub fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { if self.use_lub { self.at(&self.cause, self.fcx.param_env).lub(b, a) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 8c3a010303768..bfc5419cc92bf 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,3 +1,4 @@ +use crate::check::coercion::Coerce; use crate::check::FnCtxt; use rustc_infer::infer::InferOk; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -8,8 +9,9 @@ use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::{is_range_literal, Node}; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::{self, AssocItem, Ty}; +use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -539,6 +541,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some((sp, "consider removing the borrow", code)); } } + ( + _, + &ty::RawPtr(TypeAndMut { ty: _, mutbl: hir::Mutability::Not }), + &ty::Ref(_, _, hir::Mutability::Not), + ) => { + let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); + // We don't ever need two-phase here since we throw out the result of the coercion + let coerce = Coerce::new(self, cause, AllowTwoPhase::No); + + if let Some(steps) = + coerce.autoderef(sp, checked_ty).skip(1).find_map(|(referent_ty, steps)| { + coerce + .unify( + coerce.tcx.mk_ptr(ty::TypeAndMut { + mutbl: hir::Mutability::Not, + ty: referent_ty, + }), + expected, + ) + .ok() + .map(|_| steps) + }) + { + // The pointer type implements `Copy` trait so the suggestion is always valid. + if let Ok(code) = sm.span_to_snippet(sp) { + if code.starts_with('&') { + let derefs = "*".repeat(steps - 1); + let message = "consider dereferencing the reference"; + let suggestion = format!("&{}{}", derefs, code[1..].to_string()); + return Some((sp, message, suggestion)); + } + } + } + } _ if sp == expr.span && !is_macro => { // Check for `Deref` implementations by constructing a predicate to // prove: `::Output == U` diff --git a/src/test/ui/issues/issue-32122-1.fixed b/src/test/ui/issues/issue-32122-1.fixed new file mode 100644 index 0000000000000..4fc5f64ff9a45 --- /dev/null +++ b/src/test/ui/issues/issue-32122-1.fixed @@ -0,0 +1,17 @@ +// run-rustfix +use std::ops::Deref; + +struct Foo(u8); + +impl Deref for Foo { + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let a = Foo(0); + // Should suggest `&*` when coercing &ty to *const ty + let _: *const u8 = &*a; //~ ERROR mismatched types +} diff --git a/src/test/ui/issues/issue-32122-1.rs b/src/test/ui/issues/issue-32122-1.rs new file mode 100644 index 0000000000000..3c4859f07a2e7 --- /dev/null +++ b/src/test/ui/issues/issue-32122-1.rs @@ -0,0 +1,17 @@ +// run-rustfix +use std::ops::Deref; + +struct Foo(u8); + +impl Deref for Foo { + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let a = Foo(0); + // Should suggest `&*` when coercing &ty to *const ty + let _: *const u8 = &a; //~ ERROR mismatched types +} diff --git a/src/test/ui/issues/issue-32122-1.stderr b/src/test/ui/issues/issue-32122-1.stderr new file mode 100644 index 0000000000000..313de275c53ee --- /dev/null +++ b/src/test/ui/issues/issue-32122-1.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/issue-32122-1.rs:16:24 + | +LL | let _: *const u8 = &a; + | --------- ^^ + | | | + | | expected `u8`, found struct `Foo` + | | help: consider dereferencing the reference: `&*a` + | expected due to this + | + = note: expected raw pointer `*const u8` + found reference `&Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-32122-2.fixed b/src/test/ui/issues/issue-32122-2.fixed new file mode 100644 index 0000000000000..cee0e59297657 --- /dev/null +++ b/src/test/ui/issues/issue-32122-2.fixed @@ -0,0 +1,28 @@ +// run-rustfix +use std::ops::Deref; +struct Bar(u8); +struct Foo(Bar); +struct Emm(Foo); +impl Deref for Bar{ + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Foo { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Emm { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +fn main() { + let a = Emm(Foo(Bar(0))); + // Should suggest `&***` even when deref is pretty deep + let _: *const u8 = &***a; //~ ERROR mismatched types +} diff --git a/src/test/ui/issues/issue-32122-2.rs b/src/test/ui/issues/issue-32122-2.rs new file mode 100644 index 0000000000000..39e9df4224e74 --- /dev/null +++ b/src/test/ui/issues/issue-32122-2.rs @@ -0,0 +1,28 @@ +// run-rustfix +use std::ops::Deref; +struct Bar(u8); +struct Foo(Bar); +struct Emm(Foo); +impl Deref for Bar{ + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Foo { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Emm { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +fn main() { + let a = Emm(Foo(Bar(0))); + // Should suggest `&***` even when deref is pretty deep + let _: *const u8 = &a; //~ ERROR mismatched types +} diff --git a/src/test/ui/issues/issue-32122-2.stderr b/src/test/ui/issues/issue-32122-2.stderr new file mode 100644 index 0000000000000..959a49507e4f5 --- /dev/null +++ b/src/test/ui/issues/issue-32122-2.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/issue-32122-2.rs:27:24 + | +LL | let _: *const u8 = &a; + | --------- ^^ + | | | + | | expected `u8`, found struct `Emm` + | | help: consider dereferencing the reference: `&***a` + | expected due to this + | + = note: expected raw pointer `*const u8` + found reference `&Emm` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`.