diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1302027aabb36..b88b8f9d37aca 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2374,6 +2374,18 @@ rustc_queries! { } } + query check_constant_safe_to_evaluate( + key: ty::CanonicalQueryInput< + TyCtxt<'tcx>, + ty::ParamEnvAnd<'tcx, ty::UnevaluatedConst<'tcx>>, + > + ) -> bool { + desc { |tcx| + "checking constant `{}` is safe to evaluate", + tcx.def_path_str(key.canonical.value.into_parts().1.def) + } + } + query method_autoderef_steps( goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 105cb9175717d..1ddfaa827d758 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -28,6 +28,7 @@ use std::ops::ControlFlow; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; +use rustc_infer::infer::canonical::OriginalQueryValues; pub use rustc_infer::traits::*; use rustc_middle::query::Providers; use rustc_middle::span_bug; @@ -545,9 +546,10 @@ pub fn try_evaluate_const<'tcx>( | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers), ty::ConstKind::Unevaluated(uv) => { // Postpone evaluation of constants that depend on generic parameters or - // inference variables. + // inference variables. Also ensure that constants are wf before passing + // them onto CTFE. // - // We use `TypingMode::PostAnalysis` here which is not *technically* correct + // We use `TypingMode::PostAnalysis` here which is not *technically* correct // to be revealing opaque types here as borrowcheck has not run yet. However, // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). @@ -555,65 +557,119 @@ pub fn try_evaluate_const<'tcx>( // // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself // instead of having this logic here - let (args, typing_env) = if tcx.features().generic_const_exprs() - && uv.has_non_region_infer() - { - // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause - // inference variables and generic parameters to show up in `ty::Const` even though the anon const - // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. - match tcx.thir_abstract_const(uv.def) { - Ok(Some(ct)) => { - let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); - if let Err(e) = ct.error_reported() { - return Err(EvaluateConstErr::EvaluationFailure(e)); - } else if ct.has_non_region_infer() || ct.has_non_region_param() { - // If the anon const *does* actually use generic parameters or inference variables from - // the generic arguments provided for it, then we should *not* attempt to evaluate it. - return Err(EvaluateConstErr::HasGenericsOrInfers); - } else { - let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args); - let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) - .with_post_analysis_normalized(tcx); + let (args, typing_env) = if tcx.features().generic_const_exprs() { + // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system + // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason + // about if you have to consider gce whatsoever. + // + // We don't bother trying to ensure GCE constants are WF before passing them to CTFE as it would cause + // query cycles on almost every single call to this function. + + if uv.has_non_region_infer() || uv.has_non_region_param() { + // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause + // inference variables and generic parameters to show up in `ty::Const` even though the anon const + // does not actually make use of them. We handle this case specially and attempt to evaluate anyway. + match tcx.thir_abstract_const(uv.def) { + Ok(Some(ct)) => { + let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args)); + if let Err(e) = ct.error_reported() { + return Err(EvaluateConstErr::EvaluationFailure(e)); + } else if ct.has_non_region_infer() || ct.has_non_region_param() { + // If the anon const *does* actually use generic parameters or inference variables from + // the generic arguments provided for it, then we should *not* attempt to evaluate it. + return Err(EvaluateConstErr::HasGenericsOrInfers); + } else { + let args = + replace_param_and_infer_args_with_placeholder(tcx, uv.args); + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (args, typing_env) + } + } + Err(_) | Ok(None) => { + let args = GenericArgs::identity_for_item(tcx, uv.def); + let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); (args, typing_env) } } - Err(_) | Ok(None) => { - let args = GenericArgs::identity_for_item(tcx, uv.def); - let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); - (args, typing_env) - } + } else { + let typing_env = infcx + .typing_env(tcx.erase_regions(param_env)) + .with_post_analysis_normalized(tcx); + (uv.args, typing_env) } - } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() { + } else if !tcx.features().min_generic_const_args() + && !tcx.features().associated_const_equality() + // We check for anon consts so that when `associated_const_equality` bounds are + // lowered on stable we still handle them correctly to avoid ICEs in CTFE. + && tcx.def_kind(uv.def) == DefKind::AnonConst + { // FIXME: remove this when `const_evaluatable_unchecked` is a hard error. // - // Diagnostics will sometimes replace the identity args of anon consts in - // array repeat expr counts with inference variables so we have to handle this - // even though it is not something we should ever actually encounter. - // - // Array repeat expr counts are allowed to syntactically use generic parameters - // but must not actually depend on them in order to evalaute successfully. This means - // that it is actually fine to evalaute them in their own environment rather than with - // the actually provided generic arguments. - tcx.dcx().delayed_bug( - "Encountered anon const with inference variable args but no error reported", - ); + // Under `min_const_generics` the only place we can encounter generics in type system + // consts is for the `const_evaluatable_unchecked` future compat lint. We don't care + // to handle them in important ways (e.g. deferring evaluation) so we handle it separately. + + if uv.has_non_region_infer() { + // Diagnostics will sometimes replace the identity args of anon consts in + // array repeat expr counts with inference variables so we have to handle this + // even though it is not something we should ever actually encounter. + // + // Array repeat expr counts are allowed to syntactically use generic parameters + // but must not actually depend on them in order to evalaute successfully. This means + // that it is actually fine to evalaute them in their own environment rather than with + // the actually provided generic arguments. + tcx.dcx().delayed_bug( + "Encountered anon const with inference variable args but no error reported", + ); + } + // Generic arguments to anon consts in the type system are never meaningful under mcg, + // there either are no arguments or its a repeat count and the arguments must not be + // depended on for evaluation. let args = GenericArgs::identity_for_item(tcx, uv.def); let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def); (args, typing_env) } else { - // FIXME: This codepath is reachable under `associated_const_equality` and in the - // future will be reachable by `min_generic_const_args`. We should handle inference - // variables and generic parameters properly instead of doing nothing. + // We are only dealing with "truly" generic/uninferred constants here: + // - `generic_const_exprs` has been handled separately in the first if + // - `min_const_generics` repeat expr count hacks have been handled in the previous if + // + // So we are free to simply defer evaluation here. This does assume that `uv.args` has + // already been normalized. + if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + return Err(EvaluateConstErr::HasGenericsOrInfers); + } + + // If we are dealing with a fully monomorphic constant then we should ensure that + // it is well formed as otherwise CTFE will ICE. For the same reasons as with + // deferring evaluation of generic/uninferred constants, we do not have to worry + // about `generic_const_expr` + if tcx.def_kind(uv.def) == DefKind::AnonConst + && tcx.predicates_of(uv.def).predicates.is_empty() + { + // ... skip doing any work + } else { + let input = infcx + .canonicalize_query(param_env.and(uv), &mut OriginalQueryValues::default()); + if !tcx.check_constant_safe_to_evaluate(input) { + let e = tcx.dcx().delayed_bug( + "Attempted to evaluate illformed constant but no error emitted", + ); + return Err(EvaluateConstErr::EvaluationFailure(e)); + } + } + let typing_env = infcx .typing_env(tcx.erase_regions(param_env)) .with_post_analysis_normalized(tcx); (uv.args, typing_env) }; - let uv = ty::UnevaluatedConst::new(uv.def, args); + let uv = ty::UnevaluatedConst::new(uv.def, args); let erased_uv = tcx.erase_regions(uv); + use rustc_middle::mir::interpret::ErrorHandled; match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) { Ok(Ok(val)) => Ok(ty::Const::new_value( @@ -697,7 +753,51 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) } -/// Normalizes the predicates and checks whether they hold in an empty environment. If this +#[instrument(level = "debug", skip(tcx), ret)] +fn check_constant_safe_to_evaluate<'tcx>( + tcx: TyCtxt<'tcx>, + input: ty::CanonicalQueryInput, ty::ParamEnvAnd<'tcx, ty::UnevaluatedConst<'tcx>>>, +) -> bool { + let (infcx, param_env_and, _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &input); + let (param_env, uv) = param_env_and.into_parts(); + + // We can't just register a wf goal for the constant as that would require evaluating the constant + // which would result in a query cycle. + let mut predicates = tcx.predicates_of(uv.def).instantiate(tcx, uv.args).predicates; + + // Specifically check trait fulfillment to avoid an error when trying to resolve + // associated items. + if let Some(trait_def_id) = tcx.trait_of_item(uv.def) { + let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, uv.args); + predicates.push(trait_ref.upcast(tcx)); + } + + let ocx = ObligationCtxt::new(&infcx); + let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); + for predicate in predicates { + let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate); + ocx.register_obligation(obligation); + } + let errors = ocx.select_all_or_error(); + + if !errors.is_empty() { + return false; + } + + // Leak check for any higher-ranked trait mismatches. + // We only need to do this in the old solver, since the new solver already + // leak-checks. + if !infcx.next_trait_solver() && infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() { + return false; + } + + // We don't check non-higher-ranked region constraints, but we don't need to as region + // constraints cant affect coherence and therefore result in overlapping impls in codegen/ctfe + // so it shouldn't matter to speculatively evaluate constants with failing region constraints. + true +} + +/// Normalizes the predicates and checks whether they hold in a given empty. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. This should not be /// used during analysis. @@ -840,6 +940,7 @@ pub fn provide(providers: &mut Providers) { specialization_enabled_in: specialize::specialization_enabled_in, instantiate_and_check_impossible_predicates, is_impossible_associated_item, + check_constant_safe_to_evaluate, ..*providers }; } diff --git a/tests/crashes/127643.rs b/tests/crashes/127643.rs deleted file mode 100644 index a4db9397bdefa..0000000000000 --- a/tests/crashes/127643.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #127643 - -#![feature(associated_const_equality)] - -fn user() -> impl Owner {} - -trait Owner { - const C: K; -} -impl Owner for () { - const C: K = K::DEFAULT; -} - -trait ConstDefault { - const DEFAULT: Self; -} - -fn main() {} diff --git a/tests/crashes/131046.rs b/tests/crashes/131046.rs deleted file mode 100644 index 2638705ae18b2..0000000000000 --- a/tests/crashes/131046.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #131046 - -trait Owner { - const C: u32; -} - -impl Owner for () { - const C: u32 = N; -} - -fn take0(_: impl Owner = { N }>) {} - -fn main() { - take0::<128>(()); -} diff --git a/tests/crashes/131406.rs b/tests/crashes/131406.rs deleted file mode 100644 index ea642f949280d..0000000000000 --- a/tests/crashes/131406.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #131406 - -trait Owner { - const C: u32 = N; -} - -impl Owner for () {} -fn take0(_: impl Owner = { N }>) {} - -fn main() { - take0::<128>(()); -} diff --git a/tests/crashes/133066.rs b/tests/crashes/133066.rs deleted file mode 100644 index 732ebb7079fd0..0000000000000 --- a/tests/crashes/133066.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #133066 -trait Owner { - const C: u32; -} - -impl Owner for () {;} - -fn take0(_: impl Owner = { N }>) {} - -fn main() { - take0::(()); -} diff --git a/tests/crashes/133199.rs b/tests/crashes/133199.rs deleted file mode 100644 index 76535fa83a6d0..0000000000000 --- a/tests/crashes/133199.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #133199 -//@ aux-build: aux133199.rs - -extern crate aux133199; - -use aux133199::FixedBitSet; - -fn main() { - FixedBitSet::<7>::new(); - //~^ ERROR -} diff --git a/tests/ui/const-generics/associated_const_equality/wf_before_evaluate-2.rs b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate-2.rs new file mode 100644 index 0000000000000..79e704c98ba20 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate-2.rs @@ -0,0 +1,20 @@ +#![feature(associated_const_equality)] + +trait Owner { + const C: K; +} +impl Owner for () { + const C: K = K::DEFAULT; +} + +trait ConstDefault { + const DEFAULT: Self; +} + +fn user() -> impl Owner {} +//~^ ERROR: the trait bound `(dyn Sized + 'static): ConstDefault` is not satisfied +//~| ERROR: the size for values of type `(dyn Sized + 'static)` cannot be known at compilation time +//~| ERROR: the trait `Sized` is not dyn compatible +//~| ERROR: mismatched types + +fn main() {} diff --git a/tests/ui/const-generics/associated_const_equality/wf_before_evaluate-2.stderr b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate-2.stderr new file mode 100644 index 0000000000000..983cecadc0a52 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate-2.stderr @@ -0,0 +1,58 @@ +error[E0277]: the trait bound `(dyn Sized + 'static): ConstDefault` is not satisfied + --> $DIR/wf_before_evaluate-2.rs:14:14 + | +LL | fn user() -> impl Owner {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ConstDefault` is not implemented for `(dyn Sized + 'static)` + | +help: this trait has no implementations, consider adding one + --> $DIR/wf_before_evaluate-2.rs:10:1 + | +LL | trait ConstDefault { + | ^^^^^^^^^^^^^^^^^^ +note: required for `()` to implement `Owner<(dyn Sized + 'static)>` + --> $DIR/wf_before_evaluate-2.rs:6:23 + | +LL | impl Owner for () { + | ------------ ^^^^^^^^ ^^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the size for values of type `(dyn Sized + 'static)` cannot be known at compilation time + --> $DIR/wf_before_evaluate-2.rs:14:14 + | +LL | fn user() -> impl Owner {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Sized + 'static)` + = help: the trait `Owner` is implemented for `()` +note: required for `()` to implement `Owner<(dyn Sized + 'static)>` + --> $DIR/wf_before_evaluate-2.rs:6:23 + | +LL | impl Owner for () { + | - ^^^^^^^^ ^^ + | | + | unsatisfied trait bound introduced here + +error[E0038]: the trait `Sized` is not dyn compatible + --> $DIR/wf_before_evaluate-2.rs:14:40 + | +LL | fn user() -> impl Owner {} + | ^ `Sized` is not dyn compatible + | + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + +error[E0308]: mismatched types + --> $DIR/wf_before_evaluate-2.rs:14:40 + | +LL | fn user() -> impl Owner {} + | ^ expected `dyn Sized`, found integer + | + = note: expected trait object `(dyn Sized + 'static)` + found type `{integer}` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0038, E0277, E0308. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.rs b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.rs new file mode 100644 index 0000000000000..8921142843d7a --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.rs @@ -0,0 +1,24 @@ +#![feature(associated_const_equality, generic_const_items)] +#![expect(incomplete_features)] + +// When we type check `main` we wind up having to prove `<() as Trait>::C<128_u64> = 128_u64` +// doing this requires normalizing `<() as Trait>::C<128_u64>`. Previously we did not check +// that consts are well formed before evaluating them (rust-lang/project-const-generics#37) so +// in attempting to get the normalized form of `<() as Trait>::C<128_u64>` we would invoke the +// ctfe machinery on a not-wf type system constant. + +trait Trait { + const C: u32; +} + +impl Trait for () { + const C: u32 = N; +} + +fn ice = { N }>>(_: T) {} +//~^ ERROR: the constant `N` is not of type `u32` + +fn main() { + ice::<128, _>(()); + //~^ ERROR: the constant `128` is not of type `u32` +} diff --git a/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.stderr b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.stderr new file mode 100644 index 0000000000000..f0d37c6f9eeda --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.stderr @@ -0,0 +1,26 @@ +error: the constant `N` is not of type `u32` + --> $DIR/wf_before_evaluate.rs:18:31 + | +LL | fn ice = { N }>>(_: T) {} + | ^^^^^^^^^^^^ expected `u32`, found `u64` + | +note: required by a const generic parameter in `Trait::C` + --> $DIR/wf_before_evaluate.rs:11:13 + | +LL | const C: u32; + | ^^^^^^^^^^^^ required by this const generic parameter in `Trait::C` + +error: the constant `128` is not of type `u32` + --> $DIR/wf_before_evaluate.rs:22:5 + | +LL | ice::<128, _>(()); + | ^^^^^^^^^^^^^^^^^ expected `u32`, found `u64` + | +note: required by a const generic parameter in `Trait::C` + --> $DIR/wf_before_evaluate.rs:11:13 + | +LL | const C: u32; + | ^^^^^^^^^^^^ required by this const generic parameter in `Trait::C` + +error: aborting due to 2 previous errors + diff --git a/tests/crashes/auxiliary/aux133199.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs similarity index 67% rename from tests/crashes/auxiliary/aux133199.rs rename to tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs index 40765d92fbfe9..a8bda14f4bd81 100644 --- a/tests/crashes/auxiliary/aux133199.rs +++ b/tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] -pub struct FixedBitSet; +pub struct Foo; -impl FixedBitSet +impl Foo where [u8; N.div_ceil(8)]: Sized, { diff --git a/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs new file mode 100644 index 0000000000000..6e20a481670f7 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs @@ -0,0 +1,10 @@ +//@ aux-build: cross-crate-2.rs + +extern crate cross_crate_2; + +use cross_crate_2::Foo; + +fn main() { + // There is an error in the aux crate but there is no way to annotate this + Foo::<7>::new(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/cross-crate-2.stderr b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.stderr new file mode 100644 index 0000000000000..9fbe826e7e9b8 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.stderr @@ -0,0 +1,22 @@ +error[E0391]: cycle detected when computing revealed normalized predicates of `cross_crate_2::Foo::::{constant#0}` + --> $DIR/auxiliary/cross-crate-2.rs:8:10 + | +LL | [u8; N.div_ceil(8)]: Sized, + | ^^^^^^^^^^^^^ + | +note: ...which requires computing normalized predicates of `cross_crate_2::Foo::::{constant#0}`... + --> $DIR/auxiliary/cross-crate-2.rs:8:10 + | +LL | [u8; N.div_ceil(8)]: Sized, + | ^^^^^^^^^^^^^ + = note: ...which again requires computing revealed normalized predicates of `cross_crate_2::Foo::::{constant#0}`, completing the cycle +note: cycle used when type-checking `main` + --> $DIR/cross-crate-2.rs:7:1 + | +LL | fn main() { + | ^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr index f454ff4e6c036..6b095f3818a16 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr @@ -1,5 +1,5 @@ error: generic parameters may not be used in const operations - --> $DIR/dependence_lint.rs:14:32 + --> $DIR/dependence_lint.rs:15:32 | LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce | ^ cannot perform const operation using `T` @@ -8,7 +8,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/dependence_lint.rs:21:37 + --> $DIR/dependence_lint.rs:22:37 | LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce | ^ cannot perform const operation using `T` @@ -27,7 +27,7 @@ LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_ = note: `#[warn(const_evaluatable_unchecked)]` on by default warning: cannot use constants which depend on generic parameters in types - --> $DIR/dependence_lint.rs:17:9 + --> $DIR/dependence_lint.rs:18:9 | LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr index 7e318f8786f39..ffc92e8e5d6fd 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr @@ -1,5 +1,5 @@ error: overly complex generic constant - --> $DIR/dependence_lint.rs:21:17 + --> $DIR/dependence_lint.rs:22:17 | LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants @@ -7,7 +7,7 @@ LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, = help: consider moving this anonymous constant into a `const` function error: unconstrained generic constant - --> $DIR/dependence_lint.rs:14:12 + --> $DIR/dependence_lint.rs:15:12 | LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,13 +28,24 @@ help: try adding a `where` bound LL | fn foo() where [(); size_of::<*mut T>()]: { | ++++++++++++++++++++++++++++++++ +error: unconstrained generic constant + --> $DIR/dependence_lint.rs:10:5 + | +LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | fn foo() where [(); size_of::<*mut T>()]: { + | ++++++++++++++++++++++++++++++++ + error: overly complex generic constant - --> $DIR/dependence_lint.rs:17:9 + --> $DIR/dependence_lint.rs:18:9 | LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error with gce | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants | = help: consider moving this anonymous constant into a `const` function -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs b/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs index 107466cd1d9ca..cb6e401ce309b 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs @@ -9,7 +9,8 @@ use std::mem::size_of; fn foo() { [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs` //[gce]~^ ERROR unconstrained - //[full]~^^ WARNING cannot use constants + //[gce]~| ERROR unconstrained + //[full]~^^^ WARNING cannot use constants //[full]~| WARNING this was previously accepted let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce //[full]~^ ERROR generic parameters may not be used diff --git a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr index ac80463480db1..52917df0da157 100644 --- a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr +++ b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/different-fn.rs:10:5 | LL | [0; size_of::>()] - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `0` + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `size_of::>()` | = note: expected constant `size_of::()` - found constant `0` + found constant `size_of::>()` error: unconstrained generic constant --> $DIR/different-fn.rs:10:9 diff --git a/tests/ui/const-generics/issues/issue-71202.rs b/tests/ui/const-generics/issues/issue-71202.rs index 0f955414d843e..37cdd942e8ca3 100644 --- a/tests/ui/const-generics/issues/issue-71202.rs +++ b/tests/ui/const-generics/issues/issue-71202.rs @@ -8,7 +8,8 @@ struct DataHolder { } impl DataHolder { - const ITEM_IS_COPY: [(); 1 - { //~ ERROR unconstrained generic constant + const ITEM_IS_COPY: [(); 1 - { + //~^ ERROR unconstrained generic constant trait NotCopy { const VALUE: bool = false; } @@ -25,7 +26,9 @@ impl DataHolder { } >::VALUE - } as usize] = []; //~ ERROR unconstrained generic constant + } as usize] = []; + //~^ ERROR unconstrained generic constant + //~| ERROR mismatched types } fn main() {} diff --git a/tests/ui/const-generics/issues/issue-71202.stderr b/tests/ui/const-generics/issues/issue-71202.stderr index cc3603d1145c3..d2669763716fb 100644 --- a/tests/ui/const-generics/issues/issue-71202.stderr +++ b/tests/ui/const-generics/issues/issue-71202.stderr @@ -2,6 +2,7 @@ error: unconstrained generic constant --> $DIR/issue-71202.rs:11:5 | LL | / const ITEM_IS_COPY: [(); 1 - { +LL | | LL | | trait NotCopy { LL | | const VALUE: bool = false; ... | @@ -12,6 +13,7 @@ LL | | } as usize] = []; help: try adding a `where` bound | LL ~ } as usize] where [(); 1 - { +LL + LL + trait NotCopy { LL + const VALUE: bool = false; LL + } @@ -32,7 +34,7 @@ LL ~ } as usize]: = []; | error: unconstrained generic constant - --> $DIR/issue-71202.rs:28:19 + --> $DIR/issue-71202.rs:29:19 | LL | } as usize] = []; | ^^ @@ -40,6 +42,7 @@ LL | } as usize] = []; help: try adding a `where` bound | LL ~ } as usize] where [(); 1 - { +LL + LL + trait NotCopy { LL + const VALUE: bool = false; LL + } @@ -59,5 +62,49 @@ LL + >::VALUE LL ~ } as usize]: = []; | -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-71202.rs:29:19 + | +LL | } as usize] = []; + | ^^ expected `1 - { + trait NotCopy { + const VALUE: bool = false; + } + + impl<__Type: ?Sized> NotCopy for __Type {} + + struct IsCopy<__Type: ?Sized>(PhantomData<__Type>); + + impl<__Type> IsCopy<__Type> + where + __Type: Sized + Copy, + { + const VALUE: bool = true; + } + + >::VALUE + } as usize`, found `0` + | + = note: expected constant `1 - { + trait NotCopy { + const VALUE: bool = false; + } + + impl<__Type: ?Sized> NotCopy for __Type {} + + struct IsCopy<__Type: ?Sized>(PhantomData<__Type>); + + impl<__Type> IsCopy<__Type> + where + __Type: Sized + Copy, + { + const VALUE: bool = true; + } + + >::VALUE + } as usize` + found constant `0` + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/issues/issue-83765.rs b/tests/ui/const-generics/issues/issue-83765.rs index 0959f771c22ed..f31c61408e9c6 100644 --- a/tests/ui/const-generics/issues/issue-83765.rs +++ b/tests/ui/const-generics/issues/issue-83765.rs @@ -3,10 +3,6 @@ trait TensorDimension { const DIM: usize; - //~^ ERROR cycle detected when resolving instance - //~| ERROR cycle detected when resolving instance - // FIXME Given the current state of the compiler its expected that we cycle here, - // but the cycle is still wrong. const ISSCALAR: bool = Self::DIM == 0; fn is_scalar(&self) -> bool { Self::ISSCALAR @@ -49,6 +45,7 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> { fn size(&self) -> [usize; DIM] { + //~^ ERROR: method not compatible with trait self.size } } @@ -56,12 +53,17 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> { type Element = T::Element; fn bget(&self, index: [usize; DIM]) -> Option { + //~^ ERROR: method not compatible with trait assert!(DIM >= T::DIM); if !self.inbounds(index) { + //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types return None; } let size = self.size(); + //~^ ERROR: unconstrained generic constant let newindex: [usize; T::DIM] = Default::default(); + //~^ ERROR: the trait bound self.reference.bget(newindex) } } @@ -82,6 +84,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSi fn size(&self) -> [usize; DIM] { //~^ ERROR: method not compatible with trait self.reference.size() + //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types } } @@ -92,6 +96,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcas fn bget(&self, index: [usize; DIM]) -> Option { //~^ ERROR: method not compatible with trait self.reference.bget(index).map(&self.closure) + //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types } } @@ -100,12 +106,14 @@ impl TensorDimension for Vec { } impl TensorSize for Vec { fn size(&self) -> [usize; 1] { + //~^ ERROR: method not compatible with trait [self.len()] } } impl Broadcastable for Vec { type Element = T; fn bget(&self, index: [usize; 1]) -> Option { + //~^ ERROR: method not compatible with trait self.get(index[0]).cloned() } } diff --git a/tests/ui/const-generics/issues/issue-83765.stderr b/tests/ui/const-generics/issues/issue-83765.stderr index 6b62012c14fc7..5a06ee7ddbc03 100644 --- a/tests/ui/const-generics/issues/issue-83765.stderr +++ b/tests/ui/const-generics/issues/issue-83765.stderr @@ -1,43 +1,23 @@ -error[E0391]: cycle detected when resolving instance `::DIM, DIM> as TensorDimension>::DIM` - --> $DIR/issue-83765.rs:5:5 - | -LL | const DIM: usize; - | ^^^^^^^^^^^^^^^^ - | -note: ...which requires computing candidate for `::DIM, DIM> as TensorDimension>`... - --> $DIR/issue-83765.rs:4:1 - | -LL | trait TensorDimension { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires resolving instance `::DIM, DIM> as TensorDimension>::DIM`, completing the cycle -note: cycle used when checking assoc item `::size` is compatible with trait definition - --> $DIR/issue-83765.rs:51:5 +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:47:5 | LL | fn size(&self) -> [usize; DIM] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0391]: cycle detected when resolving instance `::DIM, DIM> as TensorDimension>::DIM` - --> $DIR/issue-83765.rs:5:5 - | -LL | const DIM: usize; - | ^^^^^^^^^^^^^^^^ - | -note: ...which requires computing candidate for `::DIM, DIM> as TensorDimension>`... - --> $DIR/issue-83765.rs:4:1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` | -LL | trait TensorDimension { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires resolving instance `::DIM, DIM> as TensorDimension>::DIM`, completing the cycle -note: cycle used when checking assoc item `::bget` is compatible with trait definition - --> $DIR/issue-83765.rs:58:5 + = note: expected constant `Self::DIM` + found constant `DIM` + +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:55:5 | LL | fn bget(&self, index: [usize; DIM]) -> Option { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` error[E0308]: method not compatible with trait - --> $DIR/issue-83765.rs:82:5 + --> $DIR/issue-83765.rs:84:5 | LL | fn size(&self) -> [usize; DIM] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` @@ -46,7 +26,7 @@ LL | fn size(&self) -> [usize; DIM] { found constant `DIM` error[E0308]: method not compatible with trait - --> $DIR/issue-83765.rs:92:5 + --> $DIR/issue-83765.rs:96:5 | LL | fn bget(&self, index: [usize; DIM]) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` @@ -54,7 +34,127 @@ LL | fn bget(&self, index: [usize; DIM]) -> Option { = note: expected constant `Self::DIM` found constant `DIM` -error: aborting due to 4 previous errors +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:108:5 + | +LL | fn size(&self) -> [usize; 1] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1` + | + = note: expected constant `Self::DIM` + found constant `1` + +error[E0308]: method not compatible with trait + --> $DIR/issue-83765.rs:115:5 + | +LL | fn bget(&self, index: [usize; 1]) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1` + | + = note: expected constant `Self::DIM` + found constant `1` + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:58:13 + | +LL | if !self.inbounds(index) { + | ^^^^ + | +note: required by a bound in `TensorSize::inbounds` + --> $DIR/issue-83765.rs:14:39 + | +LL | fn inbounds(&self, index: [usize; Self::DIM]) -> bool { + | ^^^^^^^^^ required by this bound in `TensorSize::inbounds` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-83765.rs:58:27 + | +LL | if !self.inbounds(index) { + | ^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:63:25 + | +LL | let size = self.size(); + | ^^^^ + | +note: required by a bound in `TensorSize::size` + --> $DIR/issue-83765.rs:13:31 + | +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ required by this bound in `TensorSize::size` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0277]: the trait bound `[usize; T::DIM]: Default` is not satisfied + --> $DIR/issue-83765.rs:65:41 + | +LL | let newindex: [usize; T::DIM] = Default::default(); + | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; T::DIM]` + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> where [usize; T::DIM]: Default { + | ++++++++++++++++++++++++++++++ + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:86:24 + | +LL | self.reference.size() + | ^^^^ + | +note: required by a bound in `TensorSize::size` + --> $DIR/issue-83765.rs:13:31 + | +LL | fn size(&self) -> [usize; Self::DIM]; + | ^^^^^^^^^ required by this bound in `TensorSize::size` +help: try adding a `where` bound + | +LL | fn size(&self) -> [usize; DIM] where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-83765.rs:86:9 + | +LL | self.reference.size() + | ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM` + | + = note: expected constant `DIM` + found constant `Self::DIM` + +error: unconstrained generic constant + --> $DIR/issue-83765.rs:98:9 + | +LL | self.reference.bget(index).map(&self.closure) + | ^^^^^^^^^^^^^^ + | +note: required by a bound in `Broadcastable::bget` + --> $DIR/issue-83765.rs:21:35 + | +LL | fn bget(&self, index: [usize; Self::DIM]) -> Option; + | ^^^^^^^^^ required by this bound in `Broadcastable::bget` +help: try adding a `where` bound + | +LL | fn bget(&self, index: [usize; DIM]) -> Option where [(); Self::DIM]: { + | ++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-83765.rs:98:29 + | +LL | self.reference.bget(index).map(&self.closure) + | ^^^^^ expected `Self::DIM`, found `DIM` + | + = note: expected constant `Self::DIM` + found constant `DIM` + +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0308, E0391. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`.