diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-03-10 19:00:05 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-10 19:00:05 +0100 |
| commit | b41374598f3274e28273a447d2d7d82a6f26c1f3 (patch) | |
| tree | 4b77913b043c34b54088f7874dbe887be0980cb7 | |
| parent | ba14a836c7038da21f5e102aacc7e6d5964f79a6 (diff) | |
| parent | 109cdc754ed893edb25d2d2c1493023858c8eccb (diff) | |
| download | rust-b41374598f3274e28273a447d2d7d82a6f26c1f3.tar.gz rust-b41374598f3274e28273a447d2d7d82a6f26c1f3.zip | |
Rollup merge of #94440 - compiler-errors:issue-94282, r=lcnr
Better error for normalization errors from parent crates that use `#![feature(generic_const_exprs)]` This PR implements a somewhat rudimentary heuristic to suggest using `#![feature(generic_const_exprs)]` in a child crate when a function from a foreign crate (that may have used `#![feature(generic_const_exprs)]`) fails to normalize during codegen. cc: #79018 cc: #94287
4 files changed, 108 insertions, 25 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 6655541461d..f880b28b3c8 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -35,34 +35,14 @@ pub fn is_const_evaluatable<'cx, 'tcx>( span: Span, ) -> Result<(), NotConstEvaluatable> { debug!("is_const_evaluatable({:?})", uv); - if infcx.tcx.features().generic_const_exprs { - let tcx = infcx.tcx; + let tcx = infcx.tcx; + + if tcx.features().generic_const_exprs { match AbstractConst::new(tcx, uv)? { // We are looking at a generic abstract constant. Some(ct) => { - for pred in param_env.caller_bounds() { - match pred.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(uv) => { - if let Some(b_ct) = AbstractConst::new(tcx, uv)? { - // Try to unify with each subtree in the AbstractConst to allow for - // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` - // predicate for `(N + 1) * 2` - let result = - walk_abstract_const(tcx, b_ct, |b_ct| { - match try_unify(tcx, ct, b_ct) { - true => ControlFlow::BREAK, - false => ControlFlow::CONTINUE, - } - }); - - if let ControlFlow::Break(()) = result { - debug!("is_const_evaluatable: abstract_const ~~> ok"); - return Ok(()); - } - } - } - _ => {} // don't care - } + if satisfied_from_param_env(tcx, ct, param_env)? { + return Ok(()); } // We were unable to unify the abstract constant with @@ -163,6 +143,33 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } } + // If we're evaluating a foreign constant, under a nightly compiler without generic + // const exprs, AND it would've passed if that expression had been evaluated with + // generic const exprs, then suggest using generic const exprs. + if concrete.is_err() + && tcx.sess.is_nightly_build() + && !uv.def.did.is_local() + && !tcx.features().generic_const_exprs + && let Ok(Some(ct)) = AbstractConst::new(tcx, uv) + && satisfied_from_param_env(tcx, ct, param_env) == Ok(true) + { + tcx.sess + .struct_span_fatal( + // Slightly better span than just using `span` alone + if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span }, + "failed to evaluate generic const expression", + ) + .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") + .span_suggestion_verbose( + rustc_span::DUMMY_SP, + "consider enabling this feature", + "#![feature(generic_const_exprs)]\n".to_string(), + rustc_errors::Applicability::MaybeIncorrect, + ) + .emit(); + rustc_errors::FatalError.raise(); + } + debug!(?concrete, "is_const_evaluatable"); match concrete { Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() { @@ -178,6 +185,37 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } } +fn satisfied_from_param_env<'tcx>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Result<bool, NotConstEvaluatable> { + for pred in param_env.caller_bounds() { + match pred.kind().skip_binder() { + ty::PredicateKind::ConstEvaluatable(uv) => { + if let Some(b_ct) = AbstractConst::new(tcx, uv)? { + // Try to unify with each subtree in the AbstractConst to allow for + // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` + // predicate for `(N + 1) * 2` + let result = + walk_abstract_const(tcx, b_ct, |b_ct| match try_unify(tcx, ct, b_ct) { + true => ControlFlow::BREAK, + false => ControlFlow::CONTINUE, + }); + + if let ControlFlow::Break(()) = result { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(true); + } + } + } + _ => {} // don't care + } + } + + Ok(false) +} + /// A tree representing an anonymous constant. /// /// This is only able to represent a subset of `MIR`, diff --git a/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs b/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs new file mode 100644 index 00000000000..df454dae725 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs @@ -0,0 +1,21 @@ +#![feature(generic_const_exprs)] + +use std::str::FromStr; + +pub struct If<const CONDITION: bool>; + +pub trait True {} + +impl True for If<true> {} + +pub struct FixedI32<const FRAC: u32>; + +impl<const FRAC: u32> FromStr for FixedI32<FRAC> +where + If<{ FRAC <= 32 }>: True, +{ + type Err = (); + fn from_str(_s: &str) -> Result<Self, Self::Err> { + unimplemented!() + } +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs b/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs new file mode 100644 index 00000000000..643126a4640 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs @@ -0,0 +1,10 @@ +// aux-build:issue-94287-aux.rs +// build-fail + +extern crate issue_94287_aux; + +use std::str::FromStr; + +fn main() { + let _ = <issue_94287_aux::FixedI32<16>>::from_str(""); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr new file mode 100644 index 00000000000..c918651ba62 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr @@ -0,0 +1,14 @@ +error: failed to evaluate generic const expression + --> $DIR/auxiliary/issue-94287-aux.rs:15:8 + | +LL | If<{ FRAC <= 32 }>: True, + | ^^^^^^^^^^^^^^ + | + = note: the crate this constant originates from uses `#![feature(generic_const_exprs)]` +help: consider enabling this feature + | +LL | #![feature(generic_const_exprs)] + | + +error: aborting due to previous error + |
