From 2bbc33aaf049bd14d862333a2914bc78b4bd4f24 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 27 Mar 2020 10:56:02 +0200 Subject: [PATCH 1/6] typeck: track any errors injected during writeback and taint tables appropriately. --- src/librustc_typeck/check/writeback.rs | 20 +++++++++--- src/test/ui/issues/issue-66706.rs | 13 ++++++++ src/test/ui/issues/issue-66706.stderr | 43 ++++++++++++++++++++++++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 146fc04bc27..f9100300e3a 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -75,7 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.tables.upvar_list = mem::replace(&mut self.tables.borrow_mut().upvar_list, Default::default()); - wbcx.tables.tainted_by_errors = self.is_tainted_by_errors(); + wbcx.tables.tainted_by_errors |= self.is_tainted_by_errors(); debug!("writeback: tables for {:?} are {:#?}", item_def_id, wbcx.tables); @@ -578,14 +578,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve(&self, x: &T, span: &dyn Locatable) -> T + fn resolve(&mut self, x: &T, span: &dyn Locatable) -> T where T: TypeFoldable<'tcx>, { - let x = x.fold_with(&mut Resolver::new(self.fcx, span, self.body)); + let mut resolver = Resolver::new(self.fcx, span, self.body); + let x = x.fold_with(&mut resolver); if cfg!(debug_assertions) && x.needs_infer() { span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x); } + + // We may have introduced e.g. `ty::Error`, if inference failed, make sure + // to mark the `TypeckTables` as tainted in that case, so that downstream + // users of the tables don't produce extra errors, or worse, ICEs. + self.tables.tainted_by_errors |= resolver.replaced_with_error; + x } } @@ -613,6 +620,9 @@ struct Resolver<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, + + /// Set to `true` if any `Ty` or `ty::Const` had to be replaced with an `Error`. + replaced_with_error: bool, } impl<'cx, 'tcx> Resolver<'cx, 'tcx> { @@ -621,7 +631,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, ) -> Resolver<'cx, 'tcx> { - Resolver { tcx: fcx.tcx, infcx: fcx, span, body } + Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: false } } fn report_error(&self, t: Ty<'tcx>) { @@ -644,6 +654,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_error(t); + self.replaced_with_error = true; self.tcx().types.err } } @@ -661,6 +672,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); // FIXME: we'd like to use `self.report_error`, but it doesn't yet // accept a &'tcx ty::Const. + self.replaced_with_error = true; self.tcx().consts.err } } diff --git a/src/test/ui/issues/issue-66706.rs b/src/test/ui/issues/issue-66706.rs index 5e64f63d533..02305191f6e 100644 --- a/src/test/ui/issues/issue-66706.rs +++ b/src/test/ui/issues/issue-66706.rs @@ -10,4 +10,17 @@ fn b() { //~^ ERROR expected identifier, found reserved identifier `_` } +fn c() { + [0; [|&_: _ &_| {}; 0 ].len()] + //~^ ERROR expected `,`, found `&` + //~| ERROR mismatched types +} + +fn d() { + [0; match [|f @ &ref _| () ] {} ] + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR `match` is not allowed in a `const` + //~| ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/issues/issue-66706.stderr b/src/test/ui/issues/issue-66706.stderr index 6d290bccc7d..ea461cc5d03 100644 --- a/src/test/ui/issues/issue-66706.stderr +++ b/src/test/ui/issues/issue-66706.stderr @@ -12,6 +12,29 @@ error: expected identifier, found reserved identifier `_` LL | [0; [|f @ &ref _| {} ; 0 ].len() ]; | ^ expected identifier, found reserved identifier +error: expected `,`, found `&` + --> $DIR/issue-66706.rs:14:17 + | +LL | [0; [|&_: _ &_| {}; 0 ].len()] + | -^ expected `,` + | | + | help: missing `,` + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-66706.rs:20:26 + | +LL | [0; match [|f @ &ref _| () ] {} ] + | ^ expected identifier, found reserved identifier + +error[E0658]: `match` is not allowed in a `const` + --> $DIR/issue-66706.rs:20:9 + | +LL | [0; match [|f @ &ref _| () ] {} ] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #49146 for more information + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + error[E0282]: type annotations needed --> $DIR/issue-66706.rs:2:11 | @@ -26,7 +49,23 @@ LL | fn a() { LL | [0; [|_: _ &_| ()].len()] | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/issue-66706.rs:14:5 + | +LL | fn c() { + | - help: try adding a return type: `-> [{integer}; _]` +LL | [0; [|&_: _ &_| {}; 0 ].len()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` -Some errors have detailed explanations: E0282, E0308. +error[E0308]: mismatched types + --> $DIR/issue-66706.rs:20:5 + | +LL | fn d() { + | - help: try adding a return type: `-> [{integer}; _]` +LL | [0; match [|f @ &ref _| () ] {} ] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0282, E0308, E0658. For more information about an error, try `rustc --explain E0282`. From 38d38349f3c6aa86adfc2e32384c666ca8844b92 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 27 Mar 2020 01:46:24 +0200 Subject: [PATCH 2/6] typeck: workaround WF hole in `to_const`. --- src/librustc_typeck/check/mod.rs | 27 +++++++++++++++++-- src/test/compile-fail/issue-52443.rs | 5 ++++ .../ui/const-generics/issues/issue-62456.rs | 3 +-- .../const-generics/issues/issue-62456.stderr | 10 ++++++- .../ui/const-generics/issues/issue-62504.rs | 1 + .../const-generics/issues/issue-62504.stderr | 10 ++++++- .../ui/const-generics/issues/issue-66205.rs | 3 +-- .../const-generics/issues/issue-66205.stderr | 10 +++++++ .../ui/const-generics/issues/issue-67739.rs | 3 +-- .../const-generics/issues/issue-67739.stderr | 10 +++++++ src/test/ui/consts/const-eval/issue-52442.rs | 2 ++ .../ui/consts/const-eval/issue-52442.stderr | 20 ++++++++++++-- src/test/ui/consts/issue-52432.rs | 1 + src/test/ui/consts/issue-52432.stderr | 12 ++++++--- ...issue-69602-type-err-during-codegen-ice.rs | 1 + ...e-69602-type-err-during-codegen-ice.stderr | 10 ++++++- 16 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-66205.stderr create mode 100644 src/test/ui/const-generics/issues/issue-67739.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2db397d5c74..3aff70390fa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3311,8 +3311,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { - let c = self.tcx.hir().local_def_id(ast_c.hir_id).expect_local(); - ty::Const::from_anon_const(self.tcx, c) + let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id).expect_local(); + let c = ty::Const::from_anon_const(self.tcx, const_def_id); + + // HACK(eddyb) emulate what a `WellFormedConst` obligation would do. + // This code should be replaced with the proper WF handling ASAP. + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { + assert!(promoted.is_none()); + + // HACK(eddyb) let's hope these are always empty. + // let obligations = self.nominal_obligations(def_id, substs); + // self.out.extend(obligations); + + let cause = traits::ObligationCause::new( + self.tcx.def_span(const_def_id.to_def_id()), + self.body_id, + traits::MiscObligation, + ); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::Predicate::ConstEvaluatable(def_id, substs), + )); + } + + c } // If the type given by the user has free regions, save it for later, since diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs index 3a022230b39..ad6f4970367 100644 --- a/src/test/compile-fail/issue-52443.rs +++ b/src/test/compile-fail/issue-52443.rs @@ -8,4 +8,9 @@ fn main() { //~| WARN denote infinite loops with [(); { for _ in 0usize.. {}; 0}]; //~^ ERROR `for` is not allowed in a `const` + //~| ERROR calls in constants are limited to constant functions + //~| ERROR references in constants may only refer to immutable values + //~| ERROR calls in constants are limited to constant functions + //~| ERROR constant contains unimplemented expression type + //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 14b1190df0f..5d068eb7fc8 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,10 +1,9 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -// build-pass - fn foo() { let _ = [0u64; N + 1]; + //~^ ERROR constant expression depends on a generic parameter } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr index fc26f68d235..96a07110e73 100644 --- a/src/test/ui/const-generics/issues/issue-62456.stderr +++ b/src/test/ui/const-generics/issues/issue-62456.stderr @@ -6,5 +6,13 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default -warning: 1 warning emitted +error: constant expression depends on a generic parameter + --> $DIR/issue-62456.rs:5:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 212e16253f6..264e693a008 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -17,6 +17,7 @@ impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //~^ ERROR: mismatched types + //~| ERROR constant expression depends on a generic parameter } } diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.stderr index 4482389bbdd..a3a864f770c 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.stderr @@ -7,6 +7,14 @@ LL | ArrayHolder([0; Self::SIZE]) = note: expected array `[u32; _]` found array `[u32; _]` -error: aborting due to previous error +error: constant expression depends on a generic parameter + --> $DIR/issue-62504.rs:18:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 2e47b4d1882..73ba4fa6aae 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,10 +1,9 @@ -// check-pass - #![allow(incomplete_features, dead_code, unconditional_recursion)] #![feature(const_generics)] fn fact() { fact::<{ N - 1 }>(); + //~^ ERROR constant expression depends on a generic parameter } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr new file mode 100644 index 00000000000..2bd013e8b41 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-66205.rs:5:12 + | +LL | fact::<{ N - 1 }>(); + | ^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index 3d657b0947b..c8ee1821239 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -1,7 +1,5 @@ // Regression test for #67739 -// check-pass - #![allow(incomplete_features)] #![feature(const_generics)] @@ -12,6 +10,7 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; + //~^ ERROR constant expression depends on a generic parameter 0 } } diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.stderr new file mode 100644 index 00000000000..27a56b8eb02 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-67739.rs:12:15 + | +LL | [0u8; mem::size_of::()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/issue-52442.rs b/src/test/ui/consts/const-eval/issue-52442.rs index df4cc8e3026..07fb491015a 100644 --- a/src/test/ui/consts/const-eval/issue-52442.rs +++ b/src/test/ui/consts/const-eval/issue-52442.rs @@ -1,4 +1,6 @@ fn main() { [(); { &loop { break } as *const _ as usize } ]; //~^ ERROR `loop` is not allowed in a `const` + //~| ERROR casting pointers to integers in constants is unstable + //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index 0ea974f1f66..eda2dbf0b6b 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -7,6 +7,22 @@ LL | [(); { &loop { break } as *const _ as usize } ]; = note: see issue #52000 for more information = help: add `#![feature(const_loop)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/issue-52442.rs:2:13 + | +LL | [(); { &loop { break } as *const _ as usize } ]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -For more information about this error, try `rustc --explain E0658`. +error[E0080]: evaluation of constant value failed + --> $DIR/issue-52442.rs:2:13 + | +LL | [(); { &loop { break } as *const _ as usize } ]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0080, E0658. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-52432.rs b/src/test/ui/consts/issue-52432.rs index ded79458e63..d719bf1b971 100644 --- a/src/test/ui/consts/issue-52432.rs +++ b/src/test/ui/consts/issue-52432.rs @@ -6,4 +6,5 @@ fn main() { //~| ERROR: type annotations needed [(); &(static || {}) as *const _ as usize]; //~^ ERROR: closures cannot be static + //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/consts/issue-52432.stderr b/src/test/ui/consts/issue-52432.stderr index d25c11138f4..e9539d24118 100644 --- a/src/test/ui/consts/issue-52432.stderr +++ b/src/test/ui/consts/issue-52432.stderr @@ -16,7 +16,13 @@ error[E0282]: type annotations needed LL | [(); &(static |x| {}) as *const _ as usize]; | ^ consider giving this closure parameter a type -error: aborting due to 3 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/issue-52432.rs:7:10 + | +LL | [(); &(static || {}) as *const _ as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants -Some errors have detailed explanations: E0282, E0697. -For more information about an error, try `rustc --explain E0282`. +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0080, E0282, E0697. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs index 2c5257ce063..6ac3eb53cb3 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -19,4 +19,5 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` fn main() { let _ = [0; B::VALUE]; + //~^ ERROR constant expression depends on a generic parameter } diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index 8ae0f8b804c..175e6b0eaa0 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -13,7 +13,15 @@ LL | type MyA: TraitA; LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation -error: aborting due to 2 previous errors +error: constant expression depends on a generic parameter + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 + | +LL | let _ = [0; B::VALUE]; + | ^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0046, E0437. For more information about an error, try `rustc --explain E0046`. From 5ebd300090429ef8587b3e4026d6c268b2b23c12 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 4 Apr 2020 20:08:33 +0300 Subject: [PATCH 3/6] ty: erase lifetimes early in `ty::Const::eval`. --- src/librustc_middle/ty/sty.rs | 56 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 081e6f06b33..248a2095d0a 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2339,43 +2339,41 @@ impl<'tcx> Const<'tcx> { /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> { - let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| { + if let ConstKind::Unevaluated(did, substs, promoted) = self.val { let param_env_and_substs = param_env.with_reveal_all().and(substs); - // Avoid querying `tcx.const_eval(...)` with any inference vars. - if param_env_and_substs.needs_infer() { - return None; - } + // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` + // also does later, but we want to do it before checking for + // inference variables. + let param_env_and_substs = tcx.erase_regions(¶m_env_and_substs); + // HACK(eddyb) when the query key would contain inference variables, + // attempt using identity substs and `ParamEnv` instead, that will succeed + // when the expression doesn't depend on any parameters. + // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that + // we can call `infcx.const_eval_resolve` which handles inference variables. + let param_env_and_substs = if param_env_and_substs.needs_infer() { + tcx.param_env(did).and(InternalSubsts::identity_for_item(tcx, did)) + } else { + param_env_and_substs + }; + + // FIXME(eddyb) maybe the `const_eval_*` methods should take + // `ty::ParamEnvAnd` instead of having them separate. let (param_env, substs) = param_env_and_substs.into_parts(); - // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - tcx.const_eval_resolve(param_env, did, substs, promoted, None) - .ok() - .map(|val| Const::from_value(tcx, val, self.ty)) - }; + match tcx.const_eval_resolve(param_env, did, substs, promoted, None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Const::from_value(tcx, val, self.ty), - match self.val { - ConstKind::Unevaluated(did, substs, promoted) => { - // HACK(eddyb) when substs contain inference variables, - // attempt using identity substs instead, that will succeed - // when the expression doesn't depend on any parameters. - // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that - // we can call `infcx.const_eval_resolve` which handles inference variables. - if substs.needs_infer() { - let identity_substs = InternalSubsts::identity_for_item(tcx, did); - // The `ParamEnv` needs to match the `identity_substs`. - let identity_param_env = tcx.param_env(did); - match try_const_eval(did, identity_param_env, identity_substs, promoted) { - Some(ct) => ct.subst(tcx, substs), - None => self, - } - } else { - try_const_eval(did, param_env, substs, promoted).unwrap_or(self) - } + Err(_) => self, } - _ => self, + } else { + self } } From ad1617bb490a57988a5d8112b698ad3fdb80e42e Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 4 Apr 2020 21:23:38 +0300 Subject: [PATCH 4/6] traits/query/normalize: add some `debug!` logging for the result. --- .../traits/query/normalize.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 28d59b41e56..0da26abc330 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -59,11 +59,22 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { anon_depth: 0, }; - let value1 = value.fold_with(&mut normalizer); + let result = value.fold_with(&mut normalizer); + debug!( + "normalize::<{}>: result={:?} with {} obligations", + ::std::any::type_name::(), + result, + normalizer.obligations.len(), + ); + debug!( + "normalize::<{}>: obligations={:?}", + ::std::any::type_name::(), + normalizer.obligations, + ); if normalizer.error { Err(NoSolution) } else { - Ok(Normalized { value: value1, obligations: normalizer.obligations }) + Ok(Normalized { value: result, obligations: normalizer.obligations }) } } } From 89890294764fd0a3ff286167cc07d04e6b970336 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 4 Apr 2020 21:26:34 +0300 Subject: [PATCH 5/6] borrow_check/type_check: normalize `Aggregate` and `Call` operands. --- src/librustc_mir/borrow_check/type_check/mod.rs | 2 ++ .../ui/consts/issue-70773-mir-typeck-lt-norm.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index a118fe2db71..4dc4fb6d8e9 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1760,6 +1760,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(body, self.tcx()); + let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if from_hir_call { ConstraintCategory::CallArgument } else { @@ -2402,6 +2403,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; let operand_ty = operand.ty(body, tcx); + let operand_ty = self.normalize(operand_ty, location); if let Err(terr) = self.sub_types( operand_ty, diff --git a/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs b/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs new file mode 100644 index 00000000000..07af8310424 --- /dev/null +++ b/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs @@ -0,0 +1,15 @@ +// run-pass + +const HASH_LEN: usize = 20; +struct Hash([u8; HASH_LEN]); +fn init_hash(_: &mut [u8; HASH_LEN]) {} + +fn foo<'a>() -> &'a () { + Hash([0; HASH_LEN]); + init_hash(&mut [0; HASH_LEN]); + &() +} + +fn main() { + foo(); +} From 8bb7b7bf9c781968b44732791d52962c9a9a00fe Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Apr 2020 19:47:09 +0300 Subject: [PATCH 6/6] typeck: always expose repeat count `AnonConst`s' parent in `generics_of`. --- src/librustc_typeck/collect.rs | 20 ++++++-- ...ssociated-const-type-parameter-arrays-2.rs | 2 +- ...iated-const-type-parameter-arrays-2.stderr | 13 ++---- src/test/ui/consts/too_generic_eval_ice.rs | 7 ++- .../ui/consts/too_generic_eval_ice.stderr | 46 ++----------------- src/test/ui/issues/issue-39211.rs | 3 +- src/test/ui/issues/issue-39211.stderr | 9 ++-- 7 files changed, 36 insertions(+), 64 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 43fea82608e..a327951b3b0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1170,14 +1170,28 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { } // FIXME(#43408) enable this always when we get lazy normalization. Node::AnonConst(_) => { + let parent_id = tcx.hir().get_parent_item(hir_id); + let parent_def_id = tcx.hir().local_def_id(parent_id); + // HACK(eddyb) this provides the correct generics when // `feature(const_generics)` is enabled, so that const expressions // used with const generics, e.g. `Foo<{N+1}>`, can work at all. if tcx.features().const_generics { - let parent_id = tcx.hir().get_parent_item(hir_id); - Some(tcx.hir().local_def_id(parent_id)) + Some(parent_def_id) } else { - None + let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); + match parent_node { + // HACK(eddyb) this provides the correct generics for repeat + // expressions' count (i.e. `N` in `[x; N]`), as they shouldn't + // be able to cause query cycle errors. + Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id == hir_id => + { + Some(parent_def_id) + } + + _ => None, + } } } Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs index f1f82caf7d4..8fe79b97d9b 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs @@ -14,7 +14,7 @@ impl Foo for Def { pub fn test() { let _array = [4; ::Y]; - //~^ ERROR the trait bound `A: Foo` is not satisfied [E0277] + //~^ ERROR constant expression depends on a generic parameter } fn main() { diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr index 946a1f1a07a..0bc019b2dc8 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr @@ -1,17 +1,10 @@ -error[E0277]: the trait bound `A: Foo` is not satisfied +error: constant expression depends on a generic parameter --> $DIR/associated-const-type-parameter-arrays-2.rs:16:22 | -LL | const Y: usize; - | --------------- required by `Foo::Y` -... LL | let _array = [4; ::Y]; - | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` + | ^^^^^^^^^^^^^ | -help: consider further restricting this bound - | -LL | pub fn test() { - | ^^^^^ + = note: this may fail depending on what value the parameter takes error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs index 7e4d4dbe446..3ea5f88f07d 100644 --- a/src/test/ui/consts/too_generic_eval_ice.rs +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -4,10 +4,9 @@ impl Foo { const HOST_SIZE: usize = std::mem::size_of::(); pub fn crash() -> bool { - [5; Self::HOST_SIZE] == [6; 0] //~ ERROR no associated item named `HOST_SIZE` - //~^ the size for values of type `A` cannot be known - //~| the size for values of type `B` cannot be known - //~| binary operation `==` cannot be applied to type `[{integer}; _]` + [5; Self::HOST_SIZE] == [6; 0] + //~^ ERROR constant expression depends on a generic parameter + //~| ERROR binary operation `==` cannot be applied to type `[{integer}; _]` } } diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index 8b57d237516..8b29c533bcc 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -1,45 +1,10 @@ -error[E0599]: no associated item named `HOST_SIZE` found for struct `Foo` in the current scope - --> $DIR/too_generic_eval_ice.rs:7:19 - | -LL | pub struct Foo(A, B); - | --------------------------- associated item `HOST_SIZE` not found for this -... -LL | [5; Self::HOST_SIZE] == [6; 0] - | ^^^^^^^^^ associated item not found in `Foo` - | - = note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied: - `A: std::marker::Sized` - `B: std::marker::Sized` - -error[E0277]: the size for values of type `A` cannot be known at compilation time +error: constant expression depends on a generic parameter --> $DIR/too_generic_eval_ice.rs:7:13 | -LL | pub struct Foo(A, B); - | - required by this bound in `Foo` -LL | -LL | impl Foo { - | - this type parameter needs to be `std::marker::Sized` -... LL | [5; Self::HOST_SIZE] == [6; 0] - | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^ | - = help: the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit - -error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/too_generic_eval_ice.rs:7:13 - | -LL | pub struct Foo(A, B); - | - required by this bound in `Foo` -LL | -LL | impl Foo { - | - this type parameter needs to be `std::marker::Sized` -... -LL | [5; Self::HOST_SIZE] == [6; 0] - | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `std::marker::Sized` is not implemented for `B` - = note: to learn more, visit + = note: this may fail depending on what value the parameter takes error[E0369]: binary operation `==` cannot be applied to type `[{integer}; _]` --> $DIR/too_generic_eval_ice.rs:7:30 @@ -49,7 +14,6 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | | | [{integer}; _] -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0369, E0599. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/issues/issue-39211.rs b/src/test/ui/issues/issue-39211.rs index db101ae248c..c7b6f1d58f3 100644 --- a/src/test/ui/issues/issue-39211.rs +++ b/src/test/ui/issues/issue-39211.rs @@ -8,7 +8,8 @@ trait Mat { } fn m() { - let a = [3; M::Row::DIM]; //~ ERROR associated type `Row` not found for `M` + let a = [3; M::Row::DIM]; + //~^ ERROR constant expression depends on a generic parameter } fn main() { } diff --git a/src/test/ui/issues/issue-39211.stderr b/src/test/ui/issues/issue-39211.stderr index c14c663e5a1..c555983ea68 100644 --- a/src/test/ui/issues/issue-39211.stderr +++ b/src/test/ui/issues/issue-39211.stderr @@ -1,9 +1,10 @@ -error[E0220]: associated type `Row` not found for `M` - --> $DIR/issue-39211.rs:11:20 +error: constant expression depends on a generic parameter + --> $DIR/issue-39211.rs:11:17 | LL | let a = [3; M::Row::DIM]; - | ^^^ associated type `Row` not found + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes error: aborting due to previous error -For more information about this error, try `rustc --explain E0220`.