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 d4b9d2e359d59..dcdd40773d3bc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1422,14 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { LowerTypeRelativePathMode::Const, )? { TypeRelativePath::AssocItem(def_id, args) => { - if !self.tcx().is_type_const(def_id) { - let mut err = self.dcx().struct_span_err( - span, - "use of trait associated const without `#[type_const]`", - ); - err.note("the declaration in the trait must be marked with `#[type_const]`"); - return Err(err.emit()); - } + self.require_type_const_attribute(def_id, span)?; 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) @@ -1885,30 +1878,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_def_id: DefId, trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, - ) -> Const<'tcx> { - match self.lower_resolved_assoc_item_path( + ) -> Result, ErrorGuaranteed> { + let (item_def_id, item_args) = self.lower_resolved_assoc_item_path( span, opt_self_ty, item_def_id, trait_segment, item_segment, ty::AssocTag::Const, - ) { - Ok((item_def_id, item_args)) => { - if !self.tcx().is_type_const(item_def_id) { - let mut err = self.dcx().struct_span_err( - span, - "use of `const` in the type system without `#[type_const]`", - ); - err.note("the declaration must be marked with `#[type_const]`"); - return Const::new_error(self.tcx(), err.emit()); - } - - let uv = ty::UnevaluatedConst::new(item_def_id, item_args); - Const::new_unevaluated(self.tcx(), uv) - } - Err(guar) => Const::new_error(self.tcx(), guar), - } + )?; + self.require_type_const_attribute(item_def_id, span)?; + let uv = ty::UnevaluatedConst::new(item_def_id, item_args); + Ok(Const::new_unevaluated(self.tcx(), uv)) } /// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path. @@ -2668,6 +2649,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_const_param(def_id, hir_id) } Res::Def(DefKind::Const, did) => { + if let Err(guar) = self.require_type_const_attribute(did, span) { + return Const::new_error(self.tcx(), guar); + } + assert_eq!(opt_self_ty, None); let [leading_segments @ .., segment] = path.segments else { bug!() }; let _ = self @@ -2718,6 +2703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment, path.segments.last().unwrap(), ) + .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } Res::Def(DefKind::Static { .. }, _) => { span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") @@ -2843,6 +2829,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|l| tcx.at(expr.span).lit_to_const(l)) } + fn require_type_const_attribute( + &self, + def_id: DefId, + span: Span, + ) -> Result<(), ErrorGuaranteed> { + let tcx = self.tcx(); + if tcx.is_type_const(def_id) { + Ok(()) + } else { + let mut err = self + .dcx() + .struct_span_err(span, "use of `const` in the type system without `#[type_const]`"); + if def_id.is_local() { + let name = tcx.def_path_str(def_id); + err.span_suggestion( + tcx.def_span(def_id).shrink_to_lo(), + format!("add `#[type_const]` attribute to `{name}`"), + format!("#[type_const]\n"), + Applicability::MaybeIncorrect, + ); + } else { + err.note("only consts marked with `#[type_const]` may be used in types"); + } + Err(err.emit()) + } + } + fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); match idx { diff --git a/tests/ui/const-generics/generic_const_exprs/auxiliary/non_local_type_const.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/non_local_type_const.rs new file mode 100644 index 0000000000000..6ec1071461c54 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/auxiliary/non_local_type_const.rs @@ -0,0 +1,5 @@ +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] + +#[type_const] +pub const NON_LOCAL_CONST: char = 'a'; diff --git a/tests/ui/const-generics/generic_const_exprs/non-local-const.rs b/tests/ui/const-generics/generic_const_exprs/non-local-const.rs index 0a30cc385ac43..d0efdb2c20171 100644 --- a/tests/ui/const-generics/generic_const_exprs/non-local-const.rs +++ b/tests/ui/const-generics/generic_const_exprs/non-local-const.rs @@ -1,10 +1,12 @@ // regression test for #133808. +//@ aux-build:non_local_type_const.rs #![feature(generic_const_exprs)] #![feature(min_generic_const_args)] #![allow(incomplete_features)] #![crate_type = "lib"] +extern crate non_local_type_const; pub trait Foo {} -impl Foo for [u8; std::path::MAIN_SEPARATOR] {} -//~^ ERROR the constant `MAIN_SEPARATOR` is not of type `usize` +impl Foo for [u8; non_local_type_const::NON_LOCAL_CONST] {} +//~^ ERROR the constant `'a'` is not of type `usize` diff --git a/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr b/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr index d8df3269a19e9..3d1ec60eb908d 100644 --- a/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr +++ b/tests/ui/const-generics/generic_const_exprs/non-local-const.stderr @@ -1,10 +1,10 @@ -error: the constant `MAIN_SEPARATOR` is not of type `usize` - --> $DIR/non-local-const.rs:9:14 +error: the constant `'a'` is not of type `usize` + --> $DIR/non-local-const.rs:11:14 | -LL | impl Foo for [u8; std::path::MAIN_SEPARATOR] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char` +LL | impl Foo for [u8; non_local_type_const::NON_LOCAL_CONST] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char` | - = note: the length of array `[u8; MAIN_SEPARATOR]` must be type `usize` + = note: the length of array `[u8; 'a']` must be type `usize` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr b/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr index 7872e09676268..e06850747ff3a 100644 --- a/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr +++ b/tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr @@ -1,18 +1,26 @@ -error: use of trait associated const without `#[type_const]` +error: use of `const` in the type system without `#[type_const]` --> $DIR/assoc-const-without-type_const.rs:8:35 | LL | fn mk_array(_x: T) -> [(); T::SIZE] { | ^^^^^^^ | - = note: the declaration in the trait must be marked with `#[type_const]` +help: add `#[type_const]` attribute to `Tr::SIZE` + | +LL + #[type_const] +LL | const SIZE: usize; + | -error: use of trait associated const without `#[type_const]` +error: use of `const` in the type system without `#[type_const]` --> $DIR/assoc-const-without-type_const.rs:10:10 | LL | [(); T::SIZE] | ^^^^^^^ | - = note: the declaration in the trait must be marked with `#[type_const]` +help: add `#[type_const]` attribute to `Tr::SIZE` + | +LL + #[type_const] +LL | const SIZE: usize; + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/auxiliary/non_local_const.rs b/tests/ui/const-generics/mgca/auxiliary/non_local_const.rs new file mode 100644 index 0000000000000..19091e4780fef --- /dev/null +++ b/tests/ui/const-generics/mgca/auxiliary/non_local_const.rs @@ -0,0 +1 @@ +pub const N: usize = 2; diff --git a/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs index 68aa30bd65bbe..efab014894044 100644 --- a/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs +++ b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs @@ -3,6 +3,7 @@ #![expect(incomplete_features)] #![feature(min_generic_const_args)] +#[type_const] const C: usize = 0; pub struct A {} impl A { diff --git a/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr index 3d74d1db206e1..6b2b871ba4b98 100644 --- a/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr +++ b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for struct `A` - --> $DIR/const-arg-coherence-conflicting-methods.rs:12:6 + --> $DIR/const-arg-coherence-conflicting-methods.rs:13:6 | LL | impl A { | ^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `M` - --> $DIR/const-arg-coherence-conflicting-methods.rs:7:12 + --> $DIR/const-arg-coherence-conflicting-methods.rs:8:12 | LL | pub struct A {} | ^ -------------- @@ -15,7 +15,7 @@ LL | impl A { | +++ error[E0592]: duplicate definitions with name `fun1` - --> $DIR/const-arg-coherence-conflicting-methods.rs:9:5 + --> $DIR/const-arg-coherence-conflicting-methods.rs:10:5 | LL | fn fun1() {} | ^^^^^^^^^ duplicate definitions for `fun1` diff --git a/tests/ui/const-generics/mgca/non-local-const-without-type_const.rs b/tests/ui/const-generics/mgca/non-local-const-without-type_const.rs new file mode 100644 index 0000000000000..e98cbdf8e6175 --- /dev/null +++ b/tests/ui/const-generics/mgca/non-local-const-without-type_const.rs @@ -0,0 +1,9 @@ +// Just a test of the error message (it's different for non-local consts) +//@ aux-build:non_local_const.rs +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +extern crate non_local_const; +fn main() { + let x = [(); non_local_const::N]; + //~^ ERROR use of `const` in the type system without `#[type_const]` +} diff --git a/tests/ui/const-generics/mgca/non-local-const-without-type_const.stderr b/tests/ui/const-generics/mgca/non-local-const-without-type_const.stderr new file mode 100644 index 0000000000000..671dfa5fbb9eb --- /dev/null +++ b/tests/ui/const-generics/mgca/non-local-const-without-type_const.stderr @@ -0,0 +1,10 @@ +error: use of `const` in the type system without `#[type_const]` + --> $DIR/non-local-const-without-type_const.rs:7:18 + | +LL | let x = [(); non_local_const::N]; + | ^^^^^^^^^^^^^^^^^^ + | + = note: only consts marked with `#[type_const]` may be used in types + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs index 84ded05fdd0e3..ebbe097c226e8 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs @@ -12,6 +12,7 @@ enum MyEnum { Unit, } +#[type_const] const CONST_ITEM: u32 = 42; fn accepts_point() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr index cc6144b9c88af..dc6a700a8e126 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope - --> $DIR/tuple_ctor_erroneous.rs:29:23 + --> $DIR/tuple_ctor_erroneous.rs:30:23 | LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); | ^^^^^^^^^^^^^^^ not found in this scope @@ -10,55 +10,55 @@ LL | fn test_errors() { | +++++++++++++++++++++++++++++++++++ error: tuple constructor has 2 arguments but 1 were provided - --> $DIR/tuple_ctor_erroneous.rs:23:23 + --> $DIR/tuple_ctor_erroneous.rs:24:23 | LL | accepts_point::<{ Point(N) }>(); | ^^^^^^^^ error: tuple constructor has 2 arguments but 3 were provided - --> $DIR/tuple_ctor_erroneous.rs:26:23 + --> $DIR/tuple_ctor_erroneous.rs:27:23 | LL | accepts_point::<{ Point(N, N, N) }>(); | ^^^^^^^^^^^^^^ error: tuple constructor with invalid base path - --> $DIR/tuple_ctor_erroneous.rs:29:23 + --> $DIR/tuple_ctor_erroneous.rs:30:23 | LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); | ^^^^^^^^^^^^^^^^^^^^^ error: tuple constructor with invalid base path - --> $DIR/tuple_ctor_erroneous.rs:33:23 + --> $DIR/tuple_ctor_erroneous.rs:34:23 | LL | accepts_point::<{ non_ctor(N, N) }>(); | ^^^^^^^^^^^^^^ error: tuple constructor with invalid base path - --> $DIR/tuple_ctor_erroneous.rs:36:23 + --> $DIR/tuple_ctor_erroneous.rs:37:23 | LL | accepts_point::<{ CONST_ITEM(N, N) }>(); | ^^^^^^^^^^^^^^^^ error: the constant `Point` is not of type `Point` - --> $DIR/tuple_ctor_erroneous.rs:39:23 + --> $DIR/tuple_ctor_erroneous.rs:40:23 | LL | accepts_point::<{ Point }>(); | ^^^^^ expected `Point`, found struct constructor | note: required by a const generic parameter in `accepts_point` - --> $DIR/tuple_ctor_erroneous.rs:17:18 + --> $DIR/tuple_ctor_erroneous.rs:18:18 | LL | fn accepts_point() {} | ^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_point` error: the constant `MyEnum::::Variant` is not of type `MyEnum` - --> $DIR/tuple_ctor_erroneous.rs:42:22 + --> $DIR/tuple_ctor_erroneous.rs:43:22 | LL | accepts_enum::<{ MyEnum::Variant:: }>(); | ^^^^^^^^^^^^^^^^^^^^^^ expected `MyEnum`, found enum constructor | note: required by a const generic parameter in `accepts_enum` - --> $DIR/tuple_ctor_erroneous.rs:18:17 + --> $DIR/tuple_ctor_erroneous.rs:19:17 | LL | fn accepts_enum>() {} | ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_enum` diff --git a/tests/ui/const-generics/mgca/unmarked-free-const.rs b/tests/ui/const-generics/mgca/unmarked-free-const.rs new file mode 100644 index 0000000000000..a517231facb72 --- /dev/null +++ b/tests/ui/const-generics/mgca/unmarked-free-const.rs @@ -0,0 +1,11 @@ +// regression test, used to ICE + +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] + +const N: usize = 4; + +fn main() { + let x = [(); N]; + //~^ ERROR use of `const` in the type system without `#[type_const]` +} diff --git a/tests/ui/const-generics/mgca/unmarked-free-const.stderr b/tests/ui/const-generics/mgca/unmarked-free-const.stderr new file mode 100644 index 0000000000000..052ae39fdf67b --- /dev/null +++ b/tests/ui/const-generics/mgca/unmarked-free-const.stderr @@ -0,0 +1,14 @@ +error: use of `const` in the type system without `#[type_const]` + --> $DIR/unmarked-free-const.rs:9:18 + | +LL | let x = [(); N]; + | ^ + | +help: add `#[type_const]` attribute to `N` + | +LL + #[type_const] +LL | const N: usize = 4; + | + +error: aborting due to 1 previous error +