diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 23110d2c5c87..4c7cfde638f5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, - TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, + TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -394,7 +394,118 @@ pub trait GenericArgsLowerer<'a, 'tcx> { ) -> ty::GenericArg<'tcx>; } +struct ForbidMCGParamUsesFolder<'tcx> { + tcx: TyCtxt<'tcx>, + anon_const_def_id: LocalDefId, + span: Span, + is_self_alias: bool, +} + +impl<'tcx> ForbidMCGParamUsesFolder<'tcx> { + fn error(&self) -> ErrorGuaranteed { + let msg = if self.is_self_alias { + "generic `Self` types are currently not permitted in anonymous constants" + } else { + "generic parameters may not be used in const operations" + }; + let mut diag = self.tcx.dcx().struct_span_err(self.span, msg); + if self.is_self_alias { + let anon_const_hir_id: HirId = HirId::make_owner(self.anon_const_def_id); + let parent_impl = self.tcx.hir_parent_owner_iter(anon_const_hir_id).find_map( + |(_, node)| match node { + hir::OwnerNode::Item(hir::Item { + kind: hir::ItemKind::Impl(impl_), .. + }) => Some(impl_), + _ => None, + }, + ); + if let Some(impl_) = parent_impl { + diag.span_note(impl_.self_ty.span, "not a concrete type"); + } + } + diag.emit() + } +} + +impl<'tcx> ty::TypeFolder> for ForbidMCGParamUsesFolder<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if matches!(t.kind(), ty::Param(..)) { + return Ty::new_error(self.tcx, self.error()); + } + t.super_fold_with(self) + } + + fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { + if matches!(c.kind(), ty::ConstKind::Param(..)) { + return Const::new_error(self.tcx, self.error()); + } + c.super_fold_with(self) + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if matches!(r.kind(), ty::RegionKind::ReEarlyParam(..) | ty::RegionKind::ReLateParam(..)) { + return ty::Region::new_error(self.tcx, self.error()); + } + r + } +} + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// See `check_param_uses_if_mcg`. + /// + /// FIXME(mgca): this is pub only for instantiate_value_path and would be nice to avoid altogether + pub fn check_param_res_if_mcg_for_instantiate_value_path( + &self, + res: Res, + span: Span, + ) -> Result<(), ErrorGuaranteed> { + let tcx = self.tcx(); + let parent_def_id = self.item_def_id(); + if let Res::Def(DefKind::ConstParam, _) = res + && tcx.def_kind(parent_def_id) == DefKind::AnonConst + && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id) + { + let folder = ForbidMCGParamUsesFolder { + tcx, + anon_const_def_id: parent_def_id, + span, + is_self_alias: false, + }; + return Err(folder.error()); + } + Ok(()) + } + + /// Check for uses of generic parameters that are not in scope due to this being + /// in a non-generic anon const context. + #[must_use = "need to use transformed output"] + fn check_param_uses_if_mcg(&self, term: T, span: Span, is_self_alias: bool) -> T + where + T: ty::TypeFoldable>, + { + let tcx = self.tcx(); + let parent_def_id = self.item_def_id(); + if tcx.def_kind(parent_def_id) == DefKind::AnonConst + && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id) + // Fast path if contains no params/escaping bound vars. + && (term.has_param() || term.has_escaping_bound_vars()) + { + let mut folder = ForbidMCGParamUsesFolder { + tcx, + anon_const_def_id: parent_def_id, + span, + is_self_alias, + }; + term.fold_with(&mut folder) + } else { + term + } + } + /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] pub fn lower_lifetime( @@ -403,7 +514,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) { - self.lower_resolved_lifetime(resolved) + let region = self.lower_resolved_lifetime(resolved); + self.check_param_uses_if_mcg(region, lifetime.ident.span, false) } else { self.re_infer(lifetime.ident.span, reason) } @@ -411,7 +523,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] - pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { + fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); match resolved { @@ -1256,9 +1368,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { TypeRelativePath::AssocItem(def_id, args) => { let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); + let ty = self.check_param_uses_if_mcg(ty, span, false); Ok((ty, tcx.def_kind(def_id), def_id)) } TypeRelativePath::Variant { adt, variant_did } => { + let adt = self.check_param_uses_if_mcg(adt, span, false); Ok((adt, DefKind::Variant, variant_did)) } } @@ -1275,7 +1389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); - let (def_id, args) = match self.lower_type_relative_path( + match self.lower_type_relative_path( self_ty, hir_self_ty, segment, @@ -1292,15 +1406,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.note("the declaration in the trait must be marked with `#[type_const]`"); return Err(err.emit()); } - (def_id, args) + let ct = Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)); + let ct = self.check_param_uses_if_mcg(ct, span, false); + Ok(ct) } // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { span_bug!(span, "unexpected variant res for type associated const path") } - }; - Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args))) + } } /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path. @@ -2032,9 +2147,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { GenericsArgsErrExtend::None }, ); - tcx.types.self_param + self.check_param_uses_if_mcg(tcx.types.self_param, span, false) } - Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => { + Res::SelfTyAlias { alias_to: def_id, forbid_generic: _, .. } => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); // Try to evaluate any array length constants. @@ -2043,42 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { path.segments.iter(), GenericsArgsErrExtend::SelfTyAlias { def_id, span }, ); - // HACK(min_const_generics): Forbid generic `Self` types - // here as we can't easily do that during nameres. - // - // We do this before normalization as we otherwise allow - // ```rust - // trait AlwaysApplicable { type Assoc; } - // impl AlwaysApplicable for T { type Assoc = usize; } - // - // trait BindsParam { - // type ArrayTy; - // } - // impl BindsParam for ::Assoc { - // type ArrayTy = [u8; Self::MAX]; - // } - // ``` - // Note that the normalization happens in the param env of - // the anon const, which is empty. This is why the - // `AlwaysApplicable` impl needs a `T: ?Sized` bound for - // this to compile if we were to normalize here. - if forbid_generic && ty.has_param() { - let mut err = self.dcx().struct_span_err( - path.span, - "generic `Self` types are currently not permitted in anonymous constants", - ); - if let Some(hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Impl(impl_), - .. - })) = tcx.hir_get_if_local(def_id) - { - err.span_note(impl_.self_ty.span, "not a concrete type"); - } - let reported = err.emit(); - Ty::new_error(tcx, reported) - } else { - ty - } + self.check_param_uses_if_mcg(ty, span, true) } Res::Def(DefKind::AssocTy, def_id) => { let trait_segment = if let [modules @ .., trait_, _item] = path.segments { @@ -2138,7 +2218,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// and late-bound ones to [`ty::Bound`]. pub(crate) fn lower_ty_param(&self, hir_id: HirId) -> Ty<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(hir_id) { + + let ty = match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), @@ -2154,7 +2235,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), - } + }; + self.check_param_uses_if_mcg(ty, tcx.hir_span(hir_id), false) } /// Lower a const parameter from the HIR to our internal notion of a constant. @@ -2164,7 +2246,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); - match tcx.named_bound_var(path_hir_id) { + let ct = match tcx.named_bound_var(path_hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. @@ -2181,7 +2263,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ), Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), - } + }; + self.check_param_uses_if_mcg(ct, tcx.hir_span(path_hir_id), false) } /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const). @@ -2386,7 +2469,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Const<'tcx> { let tcx = self.tcx(); let span = path.span; - match path.res { + let ct = match path.res { Res::Def(DefKind::ConstParam, def_id) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( @@ -2475,7 +2558,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, format!("invalid Res {res:?} for const path"), ), - } + }; + self.check_param_uses_if_mcg(ct, span, false) } /// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`. @@ -2787,6 +2871,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let Some(i) = (param.index as usize).checked_sub(offset) { let (lifetime, _) = lifetimes[i]; + // FIXME(mgca): should we be calling self.check_params_use_if_mcg here too? self.lower_resolved_lifetime(lifetime).into() } else { tcx.mk_param_from_def(param) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ff85f53ddf30..339e77ac6edd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1004,6 +1004,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err_extend, ); + if let Err(e) = self.lowerer().check_param_res_if_mcg_for_instantiate_value_path(res, span) + { + return (Ty::new_error(self.tcx, e), res); + } + if let Res::Local(hid) = res { let ty = self.local_ty(span, hid); let ty = self.normalize(span, ty); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index b8a587016427..39c28c4f4e99 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -115,18 +115,6 @@ fn typeck_with_inspect<'tcx>( return tcx.typeck(typeck_root_def_id); } - // We can't handle bodies containing generic parameters even though - // these generic parameters aren't part of its `generics_of` right now. - // - // See the FIXME on `check_anon_const_invalid_param_uses`. - if tcx.features().min_generic_const_args() - && let DefKind::AnonConst = tcx.def_kind(def_id) - && let ty::AnonConstKind::MCG = tcx.anon_const_kind(def_id) - && let Err(e) = tcx.check_anon_const_invalid_param_uses(def_id) - { - e.raise_fatal(); - } - let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index d62ddc915d17..8cc66802e435 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -2,8 +2,6 @@ //! eliminated, and all its methods are now on `TyCtxt`. But the module name //! stays as `map` because there isn't an obviously better name for it. -use std::ops::ControlFlow; - use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; @@ -1090,52 +1088,6 @@ impl<'tcx> TyCtxt<'tcx> { None } - - // FIXME(mgca): this is pretty iffy. In the long term we should make - // HIR ty lowering able to return `Error` versions of types/consts when - // lowering them in contexts that aren't supposed to use generic parameters. - // - // This current impl strategy is incomplete and doesn't handle `Self` ty aliases. - pub fn check_anon_const_invalid_param_uses( - self, - anon: LocalDefId, - ) -> Result<(), ErrorGuaranteed> { - struct GenericParamVisitor<'tcx>(TyCtxt<'tcx>); - impl<'tcx> Visitor<'tcx> for GenericParamVisitor<'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - type Result = ControlFlow; - - fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { - self.0 - } - - fn visit_path( - &mut self, - path: &crate::hir::Path<'tcx>, - _id: HirId, - ) -> ControlFlow { - if let Res::Def( - DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, - _, - ) = path.res - { - let e = self.0.dcx().struct_span_err( - path.span, - "generic parameters may not be used in const operations", - ); - return ControlFlow::Break(e.emit()); - } - - intravisit::walk_path(self, path) - } - } - - let body = self.hir_maybe_body_owned_by(anon).unwrap(); - match GenericParamVisitor(self).visit_expr(&body.value) { - ControlFlow::Break(e) => Err(e), - ControlFlow::Continue(()) => Ok(()), - } - } } impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { diff --git a/tests/crashes/140891.rs b/tests/crashes/140891.rs deleted file mode 100644 index 421919403eff..000000000000 --- a/tests/crashes/140891.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #140891 -struct A {} -impl Iterator for A { - fn next() -> [(); std::mem::size_of::>] {} -} -fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs index b9537014767e..8d7ec1867857 100644 --- a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs +++ b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.rs @@ -11,7 +11,7 @@ struct Wrapper(i64); impl aux::FromSlice for Wrapper { fn validate_slice(_: &[[u8; Self::SIZE]]) -> Result<(), aux::Error> { - //~^ ERROR generic `Self` types are currently not permitted in anonymous constants + //~^ ERROR generic `Self` Ok(()) } } diff --git a/tests/ui/const-generics/ice-68875.rs b/tests/ui/const-generics/ice-68875.rs index cc9546be2c92..7bf6a824729a 100644 --- a/tests/ui/const-generics/ice-68875.rs +++ b/tests/ui/const-generics/ice-68875.rs @@ -1,7 +1,7 @@ //@ check-fail struct DataWrapper<'a> { - data: &'a [u8; Self::SIZE], //~ ERROR generic `Self` types are currently not permitted in anonymous constants + data: &'a [u8; Self::SIZE], //~ ERROR generic `Self` } impl DataWrapper<'_> { diff --git a/tests/ui/const-generics/issues/issue-56445-2.rs b/tests/ui/const-generics/issues/issue-56445-2.rs index e078c8487c72..11c844340080 100644 --- a/tests/ui/const-generics/issues/issue-56445-2.rs +++ b/tests/ui/const-generics/issues/issue-56445-2.rs @@ -5,7 +5,7 @@ impl<'a> OnDiskDirEntry<'a> { const LFN_FRAGMENT_LEN: usize = 2; fn lfn_contents(&self) -> [char; Self::LFN_FRAGMENT_LEN] { loop { } } - //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants + //~^ ERROR: generic `Self` } fn main() {} diff --git a/tests/ui/const-generics/issues/issue-56445-3.rs b/tests/ui/const-generics/issues/issue-56445-3.rs index c29df14586e2..a9a4a48ab675 100644 --- a/tests/ui/const-generics/issues/issue-56445-3.rs +++ b/tests/ui/const-generics/issues/issue-56445-3.rs @@ -2,7 +2,7 @@ pub struct Memory<'rom> { rom: &'rom [u8], ram: [u8; Self::SIZE], - //~^ ERROR: generic `Self` types are currently not permitted in anonymous constants + //~^ ERROR: generic `Self` } impl<'rom> Memory<'rom> { diff --git a/tests/ui/const-generics/issues/issue-67945-2.rs b/tests/ui/const-generics/issues/issue-67945-2.rs index ce48b3f86a65..d3c5c891f760 100644 --- a/tests/ui/const-generics/issues/issue-67945-2.rs +++ b/tests/ui/const-generics/issues/issue-67945-2.rs @@ -7,7 +7,7 @@ struct Bug { A: [(); { //[full]~^ ERROR overly complex generic constant let x: Option> = None; - //[min]~^ ERROR generic `Self` types are currently not permitted in anonymous constants + //[min]~^ ERROR generic `Self` 0 }], B: S diff --git a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs new file mode 100644 index 000000000000..0ee2b4eb45f6 --- /dev/null +++ b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.rs @@ -0,0 +1,13 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo<'a, T>() +where + 'a: 'a, + T: Trait + //~^ ERROR generic parameters may not be used in const operations +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr new file mode 100644 index 000000000000..461a26e33a3c --- /dev/null +++ b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/early-bound-param-lt-bad.rs:9:30 + | +LL | T: Trait + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs new file mode 100644 index 000000000000..d3288d00ba6e --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-7.rs @@ -0,0 +1,10 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +fn foo() -> [(); N] { + let a: [(); const { N }] = todo!(); + //~^ ERROR: generic parameters may not be used in const operations +} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr new file mode 100644 index 000000000000..1b28c861067d --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-7.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-7.rs:8:25 + | +LL | let a: [(); const { N }] = todo!(); + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs new file mode 100644 index 000000000000..368644b641df --- /dev/null +++ b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.rs @@ -0,0 +1,12 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo() +where + for<'a> T: Trait + //~^ ERROR cannot capture late-bound lifetime in constant +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr new file mode 100644 index 000000000000..0f7389cac5cd --- /dev/null +++ b/tests/ui/const-generics/mgca/higher-ranked-lts-bad.stderr @@ -0,0 +1,8 @@ +error: cannot capture late-bound lifetime in constant + --> $DIR/higher-ranked-lts-bad.rs:8:38 + | +LL | for<'a> T: Trait + | -- lifetime defined here ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/higher-ranked-lts-good.rs b/tests/ui/const-generics/mgca/higher-ranked-lts-good.rs new file mode 100644 index 000000000000..5b455bb1e71e --- /dev/null +++ b/tests/ui/const-generics/mgca/higher-ranked-lts-good.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo() +where + T: Trait fn(&'a ()); 1 }> +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs new file mode 100644 index 000000000000..5c57bdfb9024 --- /dev/null +++ b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.rs @@ -0,0 +1,12 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Trait {} + +fn foo<'a, T>() +where + T: Trait + //~^ ERROR cannot capture late-bound lifetime in constant +{} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr new file mode 100644 index 000000000000..e5c22f282544 --- /dev/null +++ b/tests/ui/const-generics/mgca/late-bound-param-lt-bad.stderr @@ -0,0 +1,11 @@ +error: cannot capture late-bound lifetime in constant + --> $DIR/late-bound-param-lt-bad.rs:8:30 + | +LL | fn foo<'a, T>() + | -- lifetime defined here +LL | where +LL | T: Trait + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/selftyalias-containing-param.rs b/tests/ui/const-generics/mgca/selftyalias-containing-param.rs new file mode 100644 index 000000000000..5ab39799078f --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyalias-containing-param.rs @@ -0,0 +1,13 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct S([(); N]); + +impl S { + fn foo() -> [(); const { let _: Self = loop {}; 1 }] { + //~^ ERROR generic `Self` + todo!() + } +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr new file mode 100644 index 000000000000..fdd3e6efdf65 --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/selftyalias-containing-param.rs:7:37 + | +LL | fn foo() -> [(); const { let _: Self = loop {}; 1 }] { + | ^^^^ + | +note: not a concrete type + --> $DIR/selftyalias-containing-param.rs:6:22 + | +LL | impl S { + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/selftyparam.rs b/tests/ui/const-generics/mgca/selftyparam.rs new file mode 100644 index 000000000000..58433405b8ca --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyparam.rs @@ -0,0 +1,9 @@ +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait Tr { + fn foo() -> [(); const { let _: Self; 1 }]; + //~^ ERROR generic parameters +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/selftyparam.stderr b/tests/ui/const-generics/mgca/selftyparam.stderr new file mode 100644 index 000000000000..376e63da9a75 --- /dev/null +++ b/tests/ui/const-generics/mgca/selftyparam.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/selftyparam.rs:5:37 + | +LL | fn foo() -> [(); const { let _: Self; 1 }]; + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs b/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs index e1cf7b579aa5..b8739b263aee 100644 --- a/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs +++ b/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs @@ -9,7 +9,7 @@ trait BindsParam { type ArrayTy; } impl BindsParam for ::Assoc { - type ArrayTy = [u8; Self::MAX]; //~ ERROR generic `Self` types + type ArrayTy = [u8; Self::MAX]; //~ ERROR generic `Self` } fn main() {} diff --git a/tests/ui/const-generics/type-relative-path-144547.min.stderr b/tests/ui/const-generics/type-relative-path-144547.min.stderr new file mode 100644 index 000000000000..1192a7434ec8 --- /dev/null +++ b/tests/ui/const-generics/type-relative-path-144547.min.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/type-relative-path-144547.rs:39:35 + | +LL | type SupportedArray = [T; ::SUPPORTED_SLOTS]; + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/type-relative-path-144547.rs b/tests/ui/const-generics/type-relative-path-144547.rs new file mode 100644 index 000000000000..b268055e1f7d --- /dev/null +++ b/tests/ui/const-generics/type-relative-path-144547.rs @@ -0,0 +1,43 @@ +// Regression test for #144547. + +//@ revisions: min mgca +//@[mgca] check-pass + +#![cfg_attr(mgca, feature(min_generic_const_args))] +#![cfg_attr(mgca, expect(incomplete_features))] + +trait UnderlyingImpl { + type InfoType: LevelInfo; + type SupportedArray; +} + +// FIXME: cfg_attr(..., type_const) is broken (search for sym::type_const in compiler/) +trait LevelInfo { + #[cfg(mgca)] + #[type_const] + const SUPPORTED_SLOTS: usize; + + #[cfg(not(mgca))] + const SUPPORTED_SLOTS: usize; +} + +struct Info; + +impl LevelInfo for Info { + #[cfg(mgca)] + #[type_const] + const SUPPORTED_SLOTS: usize = 1; + + #[cfg(not(mgca))] + const SUPPORTED_SLOTS: usize = 1; +} + +struct SomeImpl; + +impl UnderlyingImpl for SomeImpl { + type InfoType = Info; + type SupportedArray = [T; ::SUPPORTED_SLOTS]; + //[min]~^ ERROR generic parameters +} + +fn main() {}