Skip to content

Commit e6f5b97

Browse files
committed
MGCA: require #[type_const] on free consts too
1 parent 035b01b commit e6f5b97

14 files changed

+125
-50
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,14 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14221422
LowerTypeRelativePathMode::Const,
14231423
)? {
14241424
TypeRelativePath::AssocItem(def_id, args) => {
1425-
if !self.tcx().is_type_const(def_id) {
1426-
let mut err = self.dcx().struct_span_err(
1427-
span,
1428-
"use of trait associated const without `#[type_const]`",
1429-
);
1430-
err.note("the declaration in the trait must be marked with `#[type_const]`");
1431-
return Err(err.emit());
1432-
}
1425+
self.require_type_const_attribute(def_id, span)?;
14331426
let ct = Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args));
14341427
let ct = self.check_param_uses_if_mcg(ct, span, false);
14351428
Ok(ct)
@@ -1885,30 +1878,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
18851878
item_def_id: DefId,
18861879
trait_segment: Option<&hir::PathSegment<'tcx>>,
18871880
item_segment: &hir::PathSegment<'tcx>,
1888-
) -> Const<'tcx> {
1889-
match self.lower_resolved_assoc_item_path(
1881+
) -> Result<Const<'tcx>, ErrorGuaranteed> {
1882+
let (item_def_id, item_args) = self.lower_resolved_assoc_item_path(
18901883
span,
18911884
opt_self_ty,
18921885
item_def_id,
18931886
trait_segment,
18941887
item_segment,
18951888
ty::AssocTag::Const,
1896-
) {
1897-
Ok((item_def_id, item_args)) => {
1898-
if !self.tcx().is_type_const(item_def_id) {
1899-
let mut err = self.dcx().struct_span_err(
1900-
span,
1901-
"use of `const` in the type system without `#[type_const]`",
1902-
);
1903-
err.note("the declaration must be marked with `#[type_const]`");
1904-
return Const::new_error(self.tcx(), err.emit());
1905-
}
1906-
1907-
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
1908-
Const::new_unevaluated(self.tcx(), uv)
1909-
}
1910-
Err(guar) => Const::new_error(self.tcx(), guar),
1911-
}
1889+
)?;
1890+
self.require_type_const_attribute(item_def_id, span)?;
1891+
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
1892+
Ok(Const::new_unevaluated(self.tcx(), uv))
19121893
}
19131894

19141895
/// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path.
@@ -2668,6 +2649,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
26682649
self.lower_const_param(def_id, hir_id)
26692650
}
26702651
Res::Def(DefKind::Const, did) => {
2652+
if let Err(guar) = self.require_type_const_attribute(did, span) {
2653+
return Const::new_error(self.tcx(), guar);
2654+
}
2655+
26712656
assert_eq!(opt_self_ty, None);
26722657
let [leading_segments @ .., segment] = path.segments else { bug!() };
26732658
let _ = self
@@ -2718,6 +2703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
27182703
trait_segment,
27192704
path.segments.last().unwrap(),
27202705
)
2706+
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
27212707
}
27222708
Res::Def(DefKind::Static { .. }, _) => {
27232709
span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported")
@@ -2843,6 +2829,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
28432829
.map(|l| tcx.at(expr.span).lit_to_const(l))
28442830
}
28452831

2832+
fn require_type_const_attribute(
2833+
&self,
2834+
def_id: DefId,
2835+
span: Span,
2836+
) -> Result<(), ErrorGuaranteed> {
2837+
let tcx = self.tcx();
2838+
if tcx.is_type_const(def_id) {
2839+
Ok(())
2840+
} else {
2841+
let mut err = self
2842+
.dcx()
2843+
.struct_span_err(span, "use of `const` in the type system without `#[type_const]`");
2844+
if def_id.is_local() {
2845+
let name = tcx.def_path_str(def_id);
2846+
err.span_suggestion(
2847+
tcx.def_span(def_id).shrink_to_lo(),
2848+
format!("add `#[type_const]` attribute to `{name}`"),
2849+
format!("#[type_const]\n"),
2850+
Applicability::MaybeIncorrect,
2851+
);
2852+
} else {
2853+
err.note("only consts marked with `#[type_const]` may be used in types");
2854+
}
2855+
Err(err.emit())
2856+
}
2857+
}
2858+
28462859
fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
28472860
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
28482861
match idx {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(min_generic_const_args)]
2+
#![allow(incomplete_features)]
3+
4+
#[type_const]
5+
pub const NON_LOCAL_CONST: char = 'a';
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// regression test for #133808.
2+
//@ aux-build:non_local_type_const.rs
23

34
#![feature(generic_const_exprs)]
45
#![feature(min_generic_const_args)]
56
#![allow(incomplete_features)]
67
#![crate_type = "lib"]
8+
extern crate non_local_type_const;
79

810
pub trait Foo {}
9-
impl Foo for [u8; std::path::MAIN_SEPARATOR] {}
10-
//~^ ERROR the constant `MAIN_SEPARATOR` is not of type `usize`
11+
impl Foo for [u8; non_local_type_const::NON_LOCAL_CONST] {}
12+
//~^ ERROR the constant `'a'` is not of type `usize`
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: the constant `MAIN_SEPARATOR` is not of type `usize`
2-
--> $DIR/non-local-const.rs:9:14
1+
error: the constant `'a'` is not of type `usize`
2+
--> $DIR/non-local-const.rs:11:14
33
|
4-
LL | impl Foo for [u8; std::path::MAIN_SEPARATOR] {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char`
4+
LL | impl Foo for [u8; non_local_type_const::NON_LOCAL_CONST] {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char`
66
|
7-
= note: the length of array `[u8; MAIN_SEPARATOR]` must be type `usize`
7+
= note: the length of array `[u8; 'a']` must be type `usize`
88

99
error: aborting due to 1 previous error
1010

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1-
error: use of trait associated const without `#[type_const]`
1+
error: use of `const` in the type system without `#[type_const]`
22
--> $DIR/assoc-const-without-type_const.rs:8:35
33
|
44
LL | fn mk_array<T: Tr>(_x: T) -> [(); T::SIZE] {
55
| ^^^^^^^
66
|
7-
= note: the declaration in the trait must be marked with `#[type_const]`
7+
help: add `#[type_const]` attribute to `Tr::SIZE`
8+
|
9+
LL + #[type_const]
10+
LL | const SIZE: usize;
11+
|
812

9-
error: use of trait associated const without `#[type_const]`
13+
error: use of `const` in the type system without `#[type_const]`
1014
--> $DIR/assoc-const-without-type_const.rs:10:10
1115
|
1216
LL | [(); T::SIZE]
1317
| ^^^^^^^
1418
|
15-
= note: the declaration in the trait must be marked with `#[type_const]`
19+
help: add `#[type_const]` attribute to `Tr::SIZE`
20+
|
21+
LL + #[type_const]
22+
LL | const SIZE: usize;
23+
|
1624

1725
error: aborting due to 2 previous errors
1826

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub const N: usize = 2;

tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![expect(incomplete_features)]
44
#![feature(min_generic_const_args)]
55

6+
#[type_const]
67
const C: usize = 0;
78
pub struct A<const M: usize> {}
89
impl A<C> {

tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0107]: missing generics for struct `A`
2-
--> $DIR/const-arg-coherence-conflicting-methods.rs:12:6
2+
--> $DIR/const-arg-coherence-conflicting-methods.rs:13:6
33
|
44
LL | impl A {
55
| ^ expected 1 generic argument
66
|
77
note: struct defined here, with 1 generic parameter: `M`
8-
--> $DIR/const-arg-coherence-conflicting-methods.rs:7:12
8+
--> $DIR/const-arg-coherence-conflicting-methods.rs:8:12
99
|
1010
LL | pub struct A<const M: usize> {}
1111
| ^ --------------
@@ -15,7 +15,7 @@ LL | impl A<M> {
1515
| +++
1616

1717
error[E0592]: duplicate definitions with name `fun1`
18-
--> $DIR/const-arg-coherence-conflicting-methods.rs:9:5
18+
--> $DIR/const-arg-coherence-conflicting-methods.rs:10:5
1919
|
2020
LL | fn fun1() {}
2121
| ^^^^^^^^^ duplicate definitions for `fun1`
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Just a test of the error message (it's different for non-local consts)
2+
//@ aux-build:non_local_const.rs
3+
#![feature(min_generic_const_args)]
4+
#![allow(incomplete_features)]
5+
extern crate non_local_const;
6+
fn main() {
7+
let x = [(); non_local_const::N];
8+
//~^ ERROR use of `const` in the type system without `#[type_const]`
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: use of `const` in the type system without `#[type_const]`
2+
--> $DIR/non-local-const-without-type_const.rs:7:18
3+
|
4+
LL | let x = [(); non_local_const::N];
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: only consts marked with `#[type_const]` may be used in types
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)