diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 7756e51c4c5f2..395a5946424dc 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -142,7 +142,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { |err, self_ty, trait_id| { // FIXME(const_trait_impl): Do we need any of this on the non-const codepath? - let trait_ref = TraitRef::from_method(tcx, trait_id, self.args); + let trait_ref = TraitRef::from_assoc_args(tcx, trait_id, self.args); match self_ty.kind() { Param(param_ty) => { diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ce8eceebdf8d2..3d3f0085c1807 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -335,6 +335,50 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { + // Avoid evaluating instances with impossible bounds required to hold as + // this can result in executing code that should never be executed. + // + // We handle this in interpreter internals instead of at callsites (such as + // type system normalization or match exhaustiveness handling) as basically + // *every* place that we invoke CTFE should not be doing so on definitions + // with impossible bounds. Handling it here ensures that we can be certain + // that we haven't missed anywhere. + let instance_def = key.value.instance.def_id(); + if tcx.def_kind(instance_def) == DefKind::AnonConst + && let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(instance_def) + { // ... do nothing for GCE anon consts as it would cycle + } else if tcx.def_kind(instance_def) == DefKind::AnonConst + && let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(instance_def) + { + // Instead of erroring when encountering a repeat expr hack const with impossible + // preds we just FCW, as anon consts are unnameable and this code *might* wind up + // supported one day if the anon const is a path expr. + if tcx.instantiate_and_check_impossible_predicates(( + instance_def, + tcx.erase_regions(key.value.instance.args), + )) { + if let Some(local_def) = instance_def.as_local() { + tcx.node_span_lint( + rustc_session::lint::builtin::CONST_EVALUATABLE_UNCHECKED, + tcx.local_def_id_to_hir_id(local_def), + tcx.def_span(instance_def), + |lint| { + lint.primary_message( + "cannot use constants which depend on trivially-false where clauses", + ); + }, + ) + } else { + // If the repeat expr count is from some upstream crate then we don't care to + // lint on it as it should have been linted on when compiling the upstream crate. + } + }; + } else if tcx + .instantiate_and_check_impossible_predicates((instance_def, key.value.instance.args)) + { + return Err(ErrorHandled::TooGeneric(tcx.def_span(instance_def))); + } + // This shouldn't be used for statics, since statics are conceptually places, // not values -- so what we do here could break pointer identity. assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id())); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 29f819cca1fb6..fe114f1539b21 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -741,7 +741,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tcx = *self.tcx; let trait_def_id = tcx.trait_of_item(def_id).unwrap(); - let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args); + let virtual_trait_ref = + ty::TraitRef::from_assoc_args(tcx, trait_def_id, virtual_instance.args); let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4520fbe352cea..dfe9d7af3adac 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -89,6 +89,7 @@ pub(crate) fn provide(providers: &mut Providers) { opaque_ty_origin, rendered_precise_capturing_args, const_param_default, + anon_const_kind, ..*providers }; } @@ -1828,3 +1829,27 @@ fn const_param_default<'tcx>( .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args)); ty::EarlyBinder::bind(ct) } + +fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind { + let hir_id = tcx.local_def_id_to_hir_id(def); + let const_arg_id = tcx.parent_hir_id(hir_id); + match tcx.hir_node(const_arg_id) { + hir::Node::ConstArg(_) => { + if tcx.features().generic_const_exprs() { + ty::AnonConstKind::GCEConst + } else if tcx.features().min_generic_const_args() { + ty::AnonConstKind::MCGConst + } else if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Repeat(_, repeat_count), + .. + }) = tcx.hir_node(tcx.parent_hir_id(const_arg_id)) + && repeat_count.hir_id == const_arg_id + { + ty::AnonConstKind::RepeatExprCount + } else { + ty::AnonConstKind::MCGConst + } + } + _ => ty::AnonConstKind::NonTypeSystem, + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 2bed28d7b710c..d261f3f85fe71 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -104,19 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } - if in_param_ty { - // We do not allow generic parameters in anon consts if we are inside - // of a const parameter type, e.g. `struct Foo` is not allowed. - None - } else if tcx.features().generic_const_exprs() { - let parent_node = tcx.parent_hir_node(hir_id); - debug!(?parent_node); - if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node - && constant.hir_id == hir_id - { - // enum variant discriminants are not allowed to use any kind of generics - None - } else if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id) + match tcx.anon_const_kind(def_id) { + // Stable: anon consts are not able to use any generic parameters... + ty::AnonConstKind::MCGConst => None, + // we provide generics to repeat expr counts as a backwards compatibility hack. #76200 + ty::AnonConstKind::RepeatExprCount => Some(parent_did), + + // Even GCE anon const should not be allowed to use generic parameters as it would be + // trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::]`. + // + // We could potentially mirror the hack done for defaults of generic parameters but + // this case just doesn't come up much compared to `const N: u32 = ...`. Long term the + // hack for defaulted parameters should be removed eventually anyway. + ty::AnonConstKind::GCEConst if in_param_ty => None, + // GCE anon consts as a default for a generic parameter should have their provided generics + // "truncated" up to whatever generic parameter this anon const is within the default of. + // + // FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type + // parameter defaults, e.g. `T = Foo`. + ty::AnonConstKind::GCEConst + if let Some(param_id) = + tcx.hir_opt_const_param_default_param_def_id(hir_id) => { // If the def_id we are calling generics_of on is an anon ct default i.e: // @@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, }; - } else { - // HACK(eddyb) this provides the correct generics when - // `feature(generic_const_expressions)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - // - // Note that we do not supply the parent generics when using - // `min_const_generics`. - Some(parent_did) } - } else { - let parent_node = tcx.parent_hir_node(hir_id); - let parent_node = match parent_node { - Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id), - _ => parent_node, - }; - match parent_node { - // HACK(eddyb) this provides the correct generics for repeat - // expressions' count (i.e. `N` in `[x; N]`), and explicit - // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), - // as they shouldn't be able to cause query cycle errors. - Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. }) - if ct.anon_const_hir_id() == Some(hir_id) => - { - Some(parent_did) - } - Node::TyPat(_) => Some(parent_did), - // Field default values inherit the ADT's generics. - Node::Field(_) => Some(parent_did), - _ => None, + ty::AnonConstKind::GCEConst => Some(parent_did), + + // Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/` + ty::AnonConstKind::NonTypeSystem + if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) => + { + Some(parent_did) } + // Default to no generic parameters for other kinds of anon consts + ty::AnonConstKind::NonTypeSystem => None, } } Node::ConstBlock(_) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ecc2dcc5318d0..b58c05d6d72a9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -423,6 +423,7 @@ provide! { tcx, def_id, other, cdata, doc_link_traits_in_scope => { tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index)) } + anon_const_kind => { table } } pub(in crate::rmeta) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 177318bfe15e9..97f396679d429 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1562,6 +1562,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { <- tcx.explicit_implied_const_bounds(def_id).skip_binder()); } } + if let DefKind::AnonConst = def_kind { + record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id)); + } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5aa81f41b7b4d..b84d0a31d364b 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -478,6 +478,7 @@ define_tables! { doc_link_traits_in_scope: Table>, assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, + anon_const_kind: Table>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5bd111fa2f22d..fef1db8799c49 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -311,6 +311,7 @@ trivial! { rustc_middle::ty::Asyncness, rustc_middle::ty::AsyncDestructor, rustc_middle::ty::BoundVariableKind, + rustc_middle::ty::AnonConstKind, rustc_middle::ty::DeducedParamAttrs, rustc_middle::ty::Destructor, rustc_middle::ty::fast_reject::SimplifiedType, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e94f088304b19..796a53eeec5bb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2551,6 +2551,12 @@ rustc_queries! { desc { "estimating codegen size of `{}`", key } cache_on_disk_if { true } } + + query anon_const_kind(def_id: DefId) -> ty::AnonConstKind { + desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index dc5fe2d8f8b06..f1ea2152f3bd0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; -use rustc_macros::HashStable; +use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; @@ -259,3 +259,11 @@ impl<'tcx> Const<'tcx> { TypeWalker::new(self.into()) } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)] +pub enum AnonConstKind { + GCEConst, + MCGConst, + RepeatExprCount, + NonTypeSystem, +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index fa2f1cf1a1c87..8d692f18f48b1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -773,6 +773,10 @@ impl<'tcx> rustc_type_ir::inherent::Safety> for hir::Safety { } impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_feature::Features { + fn min_generic_const_args(self) -> bool { + self.min_generic_const_args() + } + fn generic_const_exprs(self) -> bool { self.generic_const_exprs() } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4de9aa5d90b01..e5d9a43aafd59 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -62,8 +62,8 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, - Value, + AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, + ValTree, ValTreeKind, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index ecd6132b3ef35..3858778bfc8fb 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! { ty::AsyncDestructor, ty::AssocItemContainer, ty::Asyncness, + ty::AnonConstKind, ty::DeducedParamAttrs, ty::Destructor, ty::Generics, diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 7641e9a16ee62..1f86c7d66889d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -143,14 +143,26 @@ where ) -> QueryResult { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { + // `ConstEvaluatable` goals don't really need to exist under `mgca` as we can assume all + // generic const args can be sucessfully evaluated as they have been checked at def site. + // + // The only reason we keep this around is so that wf checking of signatures is guaranteed + // to wind up normalizing constants emitting errors if they are ill formed. The equivalent + // check does not exist for types and results in diverging aliases not being normalized during + // wfck sometimes. + // + // Regardless, the point being that the behaviour of this goal doesn't really matter so we just + // always return `Ok` and evaluate for the CTFE side effect of emitting an error. + if self.cx().features().min_generic_const_args() { + let _ = self.evaluate_const(param_env, uv); + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + // We never return `NoSolution` here as `evaluate_const` emits an // error itself when failing to evaluate, so emitting an additional fulfillment // error in that case is unnecessary noise. This may change in the future once // evaluation failures are allowed to impact selection, e.g. generic const // expressions in impl headers or `where`-clauses. - - // FIXME(generic_const_exprs): Implement handling for generic - // const expressions here. if let Some(_normalized) = self.evaluate_const(param_env, uv) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 8ad0bf5cdf9a4..6e0d9db2bedbe 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -21,6 +21,13 @@ where self.instantiate_normalizes_to_term(goal, normalized_const.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { + // FIXME(BoxyUwU) FIXME(min_generic_const_args): I could not figure out how to write a test for this + // as we don't currently support constants in the type system with impossible predicates. It may become + // possible once `min_generic_const_args` has progressed more. + + // In coherence we should never consider an unevaluatable constant to be rigid. It may be failing due to + // impossible predicates (cc #139000 #137972), or a `panic!`, either way we don't want this to influence + // what impls are considered to overlap. self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index d2917478e4e43..0ea598cdb189d 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -342,7 +342,7 @@ pub(crate) fn transform_instance<'tcx>( let upcast_ty = match tcx.trait_of_item(def_id) { Some(trait_id) => trait_object_ty( tcx, - ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), + ty::Binder::dummy(ty::TraitRef::from_assoc_args(tcx, trait_id, instance.args)), ), // drop_in_place won't have a defining trait, skip the upcast None => instance.args.type_at(0), @@ -481,7 +481,7 @@ fn implemented_method<'tcx>( trait_method = trait_method_bound; method_id = instance.def_id(); trait_id = tcx.trait_of_item(method_id)?; - trait_ref = ty::EarlyBinder::bind(TraitRef::from_method(tcx, trait_id, instance.args)); + trait_ref = ty::EarlyBinder::bind(TraitRef::from_assoc_args(tcx, trait_id, instance.args)); trait_id } else { return None; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 39333082acdff..8eda377d8c965 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -86,9 +86,16 @@ pub fn is_const_evaluatable<'tcx>( _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), } } else if tcx.features().min_generic_const_args() { - // This is a sanity check to make sure that non-generics consts are checked to - // be evaluatable in case they aren't cchecked elsewhere. This will NOT error - // if the const uses generics, as desired. + // `ConstEvaluatable` goals don't really need to exist under `mgca` as we can assume all + // generic const args can be sucessfully evaluated as they have been checked at def site. + // + // The only reason we keep this around is so that wf checking of signatures is guaranteed + // to wind up normalizing constants emitting errors if they are ill formed. The equivalent + // check does not exist for types and results in diverging aliases not being normalized during + // wfck sometimes. + // + // Regardless, the point being that the behaviour of this goal doesn't really matter so we just + // always return `Ok` and evaluate for the CTFE side effect of emitting an error. crate::traits::evaluate_const(infcx, unexpanded_ct, param_env); Ok(()) } else { @@ -134,6 +141,8 @@ pub fn is_const_evaluatable<'tcx>( NotConstEvaluatable::MentionsInfer } else if uv.has_non_region_param() { NotConstEvaluatable::MentionsParam + } else if tcx.instantiate_and_check_impossible_predicates((uv.def, uv.args)) { + return Ok(()); } else { let guar = infcx.dcx().span_delayed_bug( span, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0987c5b42d881..c821d31d0d72d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -545,7 +545,7 @@ pub fn try_evaluate_const<'tcx>( // Postpone evaluation of constants that depend on generic parameters or // inference variables. // - // 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). @@ -553,65 +553,92 @@ 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() + let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst + && let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def) { - // `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); + // 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. + + 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 + && let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def) + { + 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", + ); } - } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() { - // 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", - ); + // The generic args of repeat expr counts under `min_const_generics` are not supposed to + // affect evaluation of the constant as this would make it a "truly" generic const arg. + // To prevent this we discard all the generic arguments and evalaute with identity args + // and in its own environment instead of the current environment we are normalizing in. 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: + // - GCEConsts have been handled separately + // - Repeat expr count back compat consts have also been handled separately + // So we are free to simply defer evaluation here. + // + // FIXME: This assumes that `args` are normalized which is not necessarily true + if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + return Err(EvaluateConstErr::HasGenericsOrInfers); + } + 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( @@ -725,7 +752,7 @@ fn instantiate_and_check_impossible_predicates<'tcx>( // Specifically check trait fulfillment to avoid an error when trying to resolve // associated items. if let Some(trait_def_id) = tcx.trait_of_item(key.0) { - let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1); + let trait_ref = ty::TraitRef::from_assoc_args(tcx, trait_def_id, key.1); predicates.push(trait_ref.upcast(tcx)); } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 66c18bed5e71a..3de7a33eab94f 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -101,7 +101,7 @@ fn resolve_associated_item<'tcx>( ) -> Result>, ErrorGuaranteed> { debug!(?trait_item_id, ?typing_env, ?trait_id, ?rcvr_args, "resolve_associated_item"); - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); + let trait_ref = ty::TraitRef::from_assoc_args(tcx, trait_id, rcvr_args); let input = typing_env.as_query_input(trait_ref); let vtbl = match tcx.codegen_select_candidate(input) { @@ -230,7 +230,7 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, args)) } traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => { - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); + let trait_ref = ty::TraitRef::from_assoc_args(tcx, trait_id, rcvr_args); if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() { // We only resolve totally substituted vtable entries. None diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 417803e75ead6..bd55a909c5ceb 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -550,6 +550,8 @@ pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { } pub trait Features: Copy { + fn min_generic_const_args(self) -> bool; + fn generic_const_exprs(self) -> bool; fn coroutine_clone(self) -> bool; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 8e10636ff657d..1568d1e76637a 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -82,7 +82,7 @@ impl TraitRef { Self::new_from_args(interner, trait_def_id, args) } - pub fn from_method(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef { + pub fn from_assoc_args(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef { let generics = interner.generics_of(trait_id); TraitRef::new(interner, trait_id, args.iter().take(generics.count())) } 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/crashes/135617.rs b/tests/crashes/135617.rs deleted file mode 100644 index ac524b823a089..0000000000000 --- a/tests/crashes/135617.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #135617 -trait Project { - const ASSOC: usize; -} - -fn foo() -where - for<'a> (): Project, -{ - [(); <() as Project>::ASSOC]; -} - -pub fn main() {} diff --git a/tests/crashes/136894.rs b/tests/crashes/136894.rs deleted file mode 100644 index 26bbb78717e1b..0000000000000 --- a/tests/crashes/136894.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #136894 -#![feature(generic_const_exprs)] -#![crate_type = "lib"] -#![allow(incomplete_features, dead_code)] - -struct X([(); f::()]) where [(); f::()]:; - -const fn f() -> usize { panic!() } diff --git a/tests/crashes/137813.rs b/tests/crashes/137813.rs deleted file mode 100644 index 5d205ee533122..0000000000000 --- a/tests/crashes/137813.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #137813 -trait AssocConst { - const A: u8; -} - -impl AssocConst for (T,) { - const A: u8 = 0; -} - -trait Trait {} - -impl Trait for () where (U,): AssocConst {} - -fn foo() -where - (): Trait, -{ -} diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs new file mode 100644 index 0000000000000..99318ef75984e --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -0,0 +1,26 @@ +// regression test for #137813 where we would assume all constants in the type system +// cannot contain inference variables, even though associated const equality syntax +// was still lowered without the feature gate enabled. + +trait AssocConst { + const A: u8; +} + +impl AssocConst for (T,) { + const A: u8 = 0; +} + +trait Trait {} + +impl Trait for () where (U,): AssocConst {} +//~^ ERROR associated const equality is incomplete +//~| ERROR the type parameter `U` is not constrained by the impl trait + +fn foo() +where + (): Trait, + //~^ ERROR type mismatch resolving +{ +} + +fn main() {} diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr new file mode 100644 index 0000000000000..e6799ec5c3aa4 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -0,0 +1,39 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/unconstrained_impl_param.rs:15:45 + | +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained_impl_param.rs:15:6 + | +LL | impl Trait for () where (U,): AssocConst {} + | ^ unconstrained type parameter + +error[E0271]: type mismatch resolving `<(_,) as AssocConst>::A == 0` + --> $DIR/unconstrained_impl_param.rs:21:5 + | +LL | (): Trait, + | ^^^^^^^^^ expected `0`, found `<(_,) as AssocConst>::A` + | + = note: expected constant `0` + found constant `<(_,) as AssocConst>::A` +note: required for `()` to implement `Trait` + --> $DIR/unconstrained_impl_param.rs:15:9 + | +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^ ^^ --------- unsatisfied trait bound introduced here + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0271, E0658. +For more information about an error, try `rustc --explain E0207`. 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..9d64e1b3ab5a3 --- /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: type mismatch resolving `<() as Trait>::C<128> == 128` +} 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..3b260ebe4f6f6 --- /dev/null +++ b/tests/ui/const-generics/associated_const_equality/wf_before_evaluate.stderr @@ -0,0 +1,31 @@ +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[E0271]: type mismatch resolving `<() as Trait>::C<128> == 128` + --> $DIR/wf_before_evaluate.rs:22:19 + | +LL | ice::<128, _>(()); + | ------------- ^^ expected `128`, found `<() as Trait>::C::<128>` + | | + | required by a bound introduced by this call + | + = note: expected constant `128` + found constant `<() as Trait>::C::<128>` +note: required by a bound in `ice` + --> $DIR/wf_before_evaluate.rs:18:31 + | +LL | fn ice = { N }>>(_: T) {} + | ^^^^^^^^^^^^ required by this bound in `ice` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack-2.rs b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack-2.rs new file mode 100644 index 0000000000000..9e7bac6578fae --- /dev/null +++ b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack-2.rs @@ -0,0 +1,31 @@ +//@ check-pass + +// Split out from `impossible_preds_repeat_expr_hack` to allow for delay span bugs to ICE + +pub trait Unimplemented<'a> {} + +trait Trait +where + for<'a> T: Unimplemented<'a>, +{ + const ASSOC: usize; +} + +impl Trait for u8 +where + for<'a> T: Unimplemented<'a>, +{ + const ASSOC: usize = 1; +} + +pub fn impossible_preds_repeat_expr_count() +where + for<'a> (): Unimplemented<'a>, +{ + // This won't actually be an error in the future but we can't really determine that + let _b = [(); 1 + 1]; + //~^ WARN: cannot use constants which depend on trivially-false where clauses + //~| WARN: this was previously accepted by the compiler +} + +fn main() {} diff --git a/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack-2.stderr b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack-2.stderr new file mode 100644 index 0000000000000..1291744149945 --- /dev/null +++ b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack-2.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/impossible_preds_repeat_expr_hack-2.rs:26:19 + | +LL | let _b = [(); 1 + 1]; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + = note: `#[warn(const_evaluatable_unchecked)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack.rs b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack.rs new file mode 100644 index 0000000000000..382a74e679d5c --- /dev/null +++ b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack.rs @@ -0,0 +1,58 @@ +// Check that we emit the `CONST_EVALUATABLE_UNCHECKED` FCW when a repeat expr +// count depends on in-scope where clauses to prove an impossible bound but does +// not otherwise depend on any in-scope generic parameters. + +pub trait Unimplemented<'a> {} + +trait Trait +where + for<'a> T: Unimplemented<'a>, +{ + const ASSOC: usize; +} + +impl Trait for u8 +where + for<'a> T: Unimplemented<'a>, +{ + const ASSOC: usize = 1; +} + +pub fn impossible_preds_repeat_expr_count() +where + for<'a> (): Unimplemented<'a>, +{ + // I expect this to potentially compile with MGCA (maybe) + let _a = [(); >::ASSOC]; + //~^ WARN: cannot use constants which depend on trivially-false where clauses + //~| WARN: this was previously accepted by the compiler + + // evaluating the anon const requires evaluating an assoc const which fails even though + // we "best effort" try to allow evaluating repeat exprs still. this prevents equating + // `1` with the anon const. + // + // I expect this to potentially compile with MGCA (maybe) + let _a: [(); 1] = [(); >::ASSOC]; + //~^ WARN: cannot use constants which depend on trivially-false where clauses + //~| WARN: this was previously accepted by the compiler + //~^^^ ERROR: mismatched types + + // This will just compiling in the future and not be an error but it's hard to + // detect this until making the FCW a hard error + let _c: [(); 2] = [(); 1 + 1]; + //~^ WARN: cannot use constants which depend on trivially-false where clauses + //~| WARN: this was previously accepted by the compiler +} + +struct Foo; + +pub fn impossible_preds_normal_arg() +where + for<'a> (): Unimplemented<'a>, +{ + let _a: Foo<1> = Foo::<{ >::ASSOC }>; + //~^ ERROR: the trait bound `for<'a> (): Unimplemented<'a>` + //~| ERROR: the trait bound `for<'a> (): Unimplemented<'a>` +} + +fn main() {} diff --git a/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack.stderr b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack.stderr new file mode 100644 index 0000000000000..898c2985f1023 --- /dev/null +++ b/tests/ui/const-generics/backcompat/impossible_preds_repeat_expr_hack.stderr @@ -0,0 +1,80 @@ +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/impossible_preds_repeat_expr_hack.rs:26:19 + | +LL | let _a = [(); >::ASSOC]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + = note: `#[warn(const_evaluatable_unchecked)]` on by default + +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/impossible_preds_repeat_expr_hack.rs:35:28 + | +LL | let _a: [(); 1] = [(); >::ASSOC]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +error[E0308]: mismatched types + --> $DIR/impossible_preds_repeat_expr_hack.rs:35:23 + | +LL | let _a: [(); 1] = [(); >::ASSOC]; + | ------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an array with a size of 1, found one with a size of >::ASSOC + | | + | expected due to this + +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/impossible_preds_repeat_expr_hack.rs:42:28 + | +LL | let _c: [(); 2] = [(); 1 + 1]; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +error[E0277]: the trait bound `for<'a> (): Unimplemented<'a>` is not satisfied + --> $DIR/impossible_preds_repeat_expr_hack.rs:53:43 + | +LL | let _a: Foo<1> = Foo::<{ >::ASSOC }>; + | ^^ the trait `for<'a> Unimplemented<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/impossible_preds_repeat_expr_hack.rs:5:1 + | +LL | pub trait Unimplemented<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait::ASSOC` + --> $DIR/impossible_preds_repeat_expr_hack.rs:9:16 + | +LL | for<'a> T: Unimplemented<'a>, + | ^^^^^^^^^^^^^^^^^ required by this bound in `Trait::ASSOC` +LL | { +LL | const ASSOC: usize; + | ----- required by a bound in this associated constant + +error[E0277]: the trait bound `for<'a> (): Unimplemented<'a>` is not satisfied + --> $DIR/impossible_preds_repeat_expr_hack.rs:53:31 + | +LL | let _a: Foo<1> = Foo::<{ >::ASSOC }>; + | ^^ the trait `for<'a> Unimplemented<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/impossible_preds_repeat_expr_hack.rs:5:1 + | +LL | pub trait Unimplemented<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required for `u8` to implement `Trait<()>` + --> $DIR/impossible_preds_repeat_expr_hack.rs:14:9 + | +LL | impl Trait for u8 + | ^^^^^^^^ ^^ +LL | where +LL | for<'a> T: Unimplemented<'a>, + | ----------------- unsatisfied trait bound introduced here + +error: aborting due to 3 previous errors; 3 warnings emitted + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. 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..77998c7ec0a14 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ aux-build: cross-crate-2.rs + +extern crate cross_crate_2; + +use cross_crate_2::Foo; + +fn main() { + Foo::<7>::new(); +} 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/generic_const_exprs/serializing_error_guaranteed.rs b/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs new file mode 100644 index 0000000000000..83b73350f83b6 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs @@ -0,0 +1,16 @@ +//@ check-pass + +// regression test for #136894. +// I (BoxyUwU) don't know what the underlying cause was here + +#![feature(generic_const_exprs)] +#![crate_type = "lib"] +#![allow(incomplete_features, dead_code)] + +struct X([(); f::()]) +where + [(); f::()]:; + +const fn f() -> usize { + panic!() +} 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`. diff --git a/tests/ui/const-generics/mgca/impossible_preds_on_anon_const.rs b/tests/ui/const-generics/mgca/impossible_preds_on_anon_const.rs new file mode 100644 index 0000000000000..164695615deb3 --- /dev/null +++ b/tests/ui/const-generics/mgca/impossible_preds_on_anon_const.rs @@ -0,0 +1,51 @@ +#![feature(generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] + +// Tests behaviour of attempting to evaluate const arguments whose wellformedness +// depends on impossible to satisfy predicates, that are satisfied from another +// trivially false clause in the environment. +// +// Additionally tests how (or if) this behaviour differs depending on whether the +// constants where trivially false where clause is global or not. + +trait Unimplemented<'a> {} + +trait Trait { + const NON_GLOBAL: usize + where + for<'a> T: Unimplemented<'a>; + + const GLOBAL: usize + where + for<'a> (): Unimplemented<'a>; +} + +impl Trait for u8 { + const NON_GLOBAL: usize = 1 + where + for<'a> T: Unimplemented<'a>; + + const GLOBAL: usize = 1 + where + for<'a> (): Unimplemented<'a>; +} + +struct Foo; + +fn non_global() +where + for<'a> (): Unimplemented<'a>, +{ + let _: Foo<1> = Foo::<{ ::NON_GLOBAL::<()> }>; + //~^ ERROR: mismatched types +} + +fn global() +where + for<'a> (): Unimplemented<'a>, +{ + let _: Foo<1> = Foo::<{ ::GLOBAL }>; + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/impossible_preds_on_anon_const.stderr b/tests/ui/const-generics/mgca/impossible_preds_on_anon_const.stderr new file mode 100644 index 0000000000000..5972b3489eaa2 --- /dev/null +++ b/tests/ui/const-generics/mgca/impossible_preds_on_anon_const.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/impossible_preds_on_anon_const.rs:39:21 + | +LL | let _: Foo<1> = Foo::<{ ::NON_GLOBAL::<()> }>; + | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `1`, found `::NON_GLOBAL::<()>` + | | + | expected due to this + | + = note: expected struct `Foo<1>` + found struct `Foo<::NON_GLOBAL::<()>>` + +error[E0308]: mismatched types + --> $DIR/impossible_preds_on_anon_const.rs:47:21 + | +LL | let _: Foo<1> = Foo::<{ ::GLOBAL }>; + | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `1`, found `::GLOBAL` + | | + | expected due to this + | + = note: expected struct `Foo<1>` + found struct `Foo<::GLOBAL>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs index 93f01c9577c04..dd00b327d2d20 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs @@ -3,7 +3,7 @@ // Ensure that we check if trivial bounds on const items hold or not. -const UNUSABLE: () = () //~ ERROR evaluation of constant value failed +const UNUSABLE: () = () where String: Copy; diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr index 407682fee5664..942e5dbd88ef4 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr @@ -1,11 +1,3 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/trivially-unsatisfied-bounds-0.rs:6:1 - | -LL | / const UNUSABLE: () = () -LL | | where -LL | | String: Copy; - | |_________________^ entering unreachable code - error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13 | @@ -21,7 +13,6 @@ LL | where LL | String: Copy; | ^^^^ required by this bound in `UNUSABLE` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0080, E0277. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs index 9243deac8704a..cf4b20ae4f630 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.rs @@ -1,12 +1,10 @@ +//@ check-pass + #![feature(generic_const_items, trivial_bounds)] #![allow(incomplete_features, dead_code, trivial_bounds)] -// FIXME(generic_const_items): This looks like a bug to me. I expected that we wouldn't emit any -// errors. I thought we'd skip the evaluation of consts whose bounds don't hold. - const UNUSED: () = () where String: Copy; -//~^^^ ERROR evaluation of constant value failed fn main() {} diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr deleted file mode 100644 index b8438a0589c5c..0000000000000 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/trivially-unsatisfied-bounds-1.rs:7:1 - | -LL | / const UNUSED: () = () -LL | | where -LL | | String: Copy; - | |_________________^ entering unreachable code - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs index 91280e49dcd7e..7f27dda20552d 100644 --- a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs +++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.rs @@ -6,6 +6,8 @@ where { [(); { let _a: Option = None; 0 }]; //~^ ERROR evaluation of constant value failed + //~^^ WARN cannot use constants which depend on trivially-false where clauses + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() {} diff --git a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr index 6c7c51db8df7f..e1d88015da06c 100644 --- a/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr +++ b/tests/ui/layout/uncomputable-due-to-trivial-bounds-ice-135138.stderr @@ -1,9 +1,19 @@ +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:10 + | +LL | [(); { let _a: Option = None; 0 }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + = note: `#[warn(const_evaluatable_unchecked)]` on by default + error[E0080]: evaluation of constant value failed --> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16 | LL | [(); { let _a: Option = None; 0 }]; | ^^ the type `Option` has an unknown layout -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs index 87f90aa438ab3..29b136c1af9f6 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.rs +++ b/tests/ui/layout/unknown-when-no-type-parameter.rs @@ -4,8 +4,16 @@ trait Project { type Assoc; } -fn foo() where (): Project { - [(); size_of::<<() as Project>::Assoc>()]; //~ ERROR evaluation of constant value failed +fn foo() +where + (): Project, +{ + [(); size_of::<<() as Project>::Assoc>()]; + //~^ WARN cannot use constants which depend on trivially-false where clauses + //~| WARN this was previously accepted by the compiler + //~| NOTE for more information, see issue #76200 + //~| NOTE `#[warn(const_evaluatable_unchecked)]` + //~^^^^^ ERROR evaluation of constant value failed //~| NOTE the type `<() as Project>::Assoc` has an unknown layout //~| NOTE inside `std::mem::size_of::<<() as Project>::Assoc>` } diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr index 35fbb11f156ab..c8d2e328726f8 100644 --- a/tests/ui/layout/unknown-when-no-type-parameter.stderr +++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr @@ -1,5 +1,15 @@ +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/unknown-when-no-type-parameter.rs:11:10 + | +LL | [(); size_of::<<() as Project>::Assoc>()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + = note: `#[warn(const_evaluatable_unchecked)]` on by default + error[E0080]: evaluation of constant value failed - --> $DIR/unknown-when-no-type-parameter.rs:8:10 + --> $DIR/unknown-when-no-type-parameter.rs:11:10 | LL | [(); size_of::<<() as Project>::Assoc>()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `<() as Project>::Assoc` has an unknown layout @@ -7,6 +17,6 @@ LL | [(); size_of::<<() as Project>::Assoc>()]; note: inside `std::mem::size_of::<<() as Project>::Assoc>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs index 973235fe65afc..e6779c0e3e0a8 100644 --- a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs +++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs @@ -7,6 +7,8 @@ where { [(); { let _a: Option<&str> = None; 0 }]; //~^ ERROR evaluation of constant value failed + //~^^ WARN cannot use constants which depend on trivially-false where clauses + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() {} diff --git a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr index 68bba2e967826..f44685fe5f3a6 100644 --- a/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr +++ b/tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr @@ -1,9 +1,19 @@ +warning: cannot use constants which depend on trivially-false where clauses + --> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:10 + | +LL | [(); { let _a: Option<&str> = None; 0 }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + = note: `#[warn(const_evaluatable_unchecked)]` on by default + error[E0080]: evaluation of constant value failed --> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16 | LL | [(); { let _a: Option<&str> = None; 0 }]; | ^^ the type `str` has an unknown layout -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/match/impossible_preds_const_pattern.rs b/tests/ui/match/impossible_preds_const_pattern.rs new file mode 100644 index 0000000000000..c457927f091ca --- /dev/null +++ b/tests/ui/match/impossible_preds_const_pattern.rs @@ -0,0 +1,61 @@ +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +trait Unimplemented<'a> {} + +trait Trait +where + for<'a> T: Unimplemented<'a>, +{ + const ASSOC: usize; +} + +impl Trait for () +where + for<'a> T: Unimplemented<'a>, +{ + const ASSOC: usize = 0; +} + +trait Global { + const ASSOC: usize + where + for<'a> (): Unimplemented<'a>; +} + +impl Global for () { + const ASSOC: usize = 0 + where + for<'a> (): Unimplemented<'a>; +} + +fn also_errors(x: usize) +where + for<'a> (): Unimplemented<'a>, +{ + // In order for match exhaustiveness to determine this match is OK, CTFE must + // be able to evalaute `<() as Trait>::ASSOC` which depends on a trivially + // false bound for well formedness. + // + // This used to succeed but now errors + match x { + <() as Trait<()>>::ASSOC => todo!(), + //~^ ERROR: constant pattern cannot depend on generic parameters + 1.. => todo!(), + } +} + +fn errors(x: usize) +where + for<'a> (): Unimplemented<'a>, +{ + // This previously would error due to the MIR for `ASSOC` being empty + // due to the globally false bound. + match x { + <() as Global>::ASSOC => todo!(), + //~^ ERROR: constant pattern cannot depend on generic parameters + 1.. => todo!(), + } +} + +fn main() {} diff --git a/tests/ui/match/impossible_preds_const_pattern.stderr b/tests/ui/match/impossible_preds_const_pattern.stderr new file mode 100644 index 0000000000000..306f55c4dd13e --- /dev/null +++ b/tests/ui/match/impossible_preds_const_pattern.stderr @@ -0,0 +1,26 @@ +error[E0158]: constant pattern cannot depend on generic parameters + --> $DIR/impossible_preds_const_pattern.rs:42:9 + | +LL | trait Trait + | -------------- +... +LL | const ASSOC: usize; + | ------------------ constant defined here +... +LL | <() as Trait<()>>::ASSOC => todo!(), + | ^^^^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter + +error[E0158]: constant pattern cannot depend on generic parameters + --> $DIR/impossible_preds_const_pattern.rs:55:9 + | +LL | trait Global { + | ------------ +LL | const ASSOC: usize + | ------------------ constant defined here +... +LL | <() as Global>::ASSOC => todo!(), + | ^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/match/trivial_bounds_on_const_pattern.rs b/tests/ui/match/trivial_bounds_on_const_pattern.rs new file mode 100644 index 0000000000000..08b3574d29bd3 --- /dev/null +++ b/tests/ui/match/trivial_bounds_on_const_pattern.rs @@ -0,0 +1,29 @@ +// Tests how we handle const patterns with trivial bounds. Previously this +// would ICE as CTFE could not handle evaluating bodies with trivial bounds. + +trait Trait +where + for<'a> [u8]: Sized, +{ + const ASSOC: [u8]; +} + +impl Trait for u8 +where + for<'a> [u8]: Sized, +{ + const ASSOC: [u8] = loop {}; +} + +fn foo() +where + for<'a> [u8]: Sized, +{ + match &[10_u8; 2] as &[u8] { + &::ASSOC => todo!(), + //~^ ERROR: constant pattern cannot depend on generic parameters + _ => todo!(), + } +} + +fn main() {} diff --git a/tests/ui/match/trivial_bounds_on_const_pattern.stderr b/tests/ui/match/trivial_bounds_on_const_pattern.stderr new file mode 100644 index 0000000000000..dbbdb70b043f8 --- /dev/null +++ b/tests/ui/match/trivial_bounds_on_const_pattern.stderr @@ -0,0 +1,15 @@ +error[E0158]: constant pattern cannot depend on generic parameters + --> $DIR/trivial_bounds_on_const_pattern.rs:23:10 + | +LL | trait Trait + | ----------- +... +LL | const ASSOC: [u8]; + | ----------------- constant defined here +... +LL | &::ASSOC => todo!(), + | ^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 9fcb26c20a682..81be8c8362e35 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -62,6 +62,11 @@ LL | / fn foo() -> Bar LL | | where LL | | Bar: Send, | |______________^ +note: ...which requires computing revealed normalized predicates of `foo::{constant#0}`... + --> $DIR/in-where-clause.rs:13:9 + | +LL | [0; 1 + 2] + | ^^^^^ = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }]`... note: ...which requires computing type of `Bar::{opaque#0}`... --> $DIR/in-where-clause.rs:5:12