MGCA: require #[type_const] on free consts too

This commit is contained in:
khyperia 2026-02-06 15:35:18 +01:00
parent 035b01b794
commit e6f5b97152
14 changed files with 125 additions and 50 deletions

View file

@ -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<Const<'tcx>, 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 {

View file

@ -0,0 +1,5 @@
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
#[type_const]
pub const NON_LOCAL_CONST: char = 'a';

View file

@ -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`

View file

@ -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

View file

@ -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<T: Tr>(_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

View file

@ -0,0 +1 @@
pub const N: usize = 2;

View file

@ -3,6 +3,7 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]
#[type_const]
const C: usize = 0;
pub struct A<const M: usize> {}
impl A<C> {

View file

@ -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<const M: usize> {}
| ^ --------------
@ -15,7 +15,7 @@ LL | impl A<M> {
| +++
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`

View file

@ -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]`
}

View file

@ -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

View file

@ -12,6 +12,7 @@ enum MyEnum<T> {
Unit,
}
#[type_const]
const CONST_ITEM: u32 = 42;
fn accepts_point<const P: Point>() {}

View file

@ -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<const N: usize, const UnresolvedIdent: /* Type */>() {
| +++++++++++++++++++++++++++++++++++
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<const P: Point>() {}
| ^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_point`
error: the constant `MyEnum::<u32>::Variant` is not of type `MyEnum<u32>`
--> $DIR/tuple_ctor_erroneous.rs:42:22
--> $DIR/tuple_ctor_erroneous.rs:43:22
|
LL | accepts_enum::<{ MyEnum::Variant::<u32> }>();
| ^^^^^^^^^^^^^^^^^^^^^^ expected `MyEnum<u32>`, 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<const E: MyEnum<u32>>() {}
| ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_enum`

View file

@ -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]`
}

View file

@ -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