Skip to content

Commit ea5affa

Browse files
authored
Rollup merge of rust-lang#74159 - lcnr:const-generic-ty-decl, r=varkor
forbid generic params in the type of const params implements and closes rust-lang#74152 fixes rust-lang#74101, closes rust-lang#71169, fixes rust-lang#73491, closes rust-lang#62878 @eddyb and I talked [on zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/type.20of.20const.20parameters/near/203405696) about this and we probably want to also forbid generic consts in the default type of a parameter, e.g. `struct Foo<T, U = [u8; std::mem::size_of::<T>()]>`, this is currently still allowed and I will probably fix that in a followup PR. r? @varkor @eddyb
2 parents 2f074e0 + 09ba0bd commit ea5affa

22 files changed

+271
-36
lines changed

src/librustc_error_codes/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ E0766: include_str!("./error_codes/E0766.md"),
452452
E0767: include_str!("./error_codes/E0767.md"),
453453
E0768: include_str!("./error_codes/E0768.md"),
454454
E0769: include_str!("./error_codes/E0769.md"),
455+
E0770: include_str!("./error_codes/E0770.md"),
455456
;
456457
// E0006, // merged with E0005
457458
// E0008, // cannot bind by-move into a pattern guard

src/librustc_error_codes/error_codes/E0671.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Const parameters cannot depend on type parameters.
44
The following is therefore invalid:
55

6-
```compile_fail,E0741
6+
```compile_fail,E0770
77
#![feature(const_generics)]
88
99
fn const_id<T, const N: T>() -> T { // error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
The type of a const parameter references other generic parameters.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0770
6+
#![feature(const_generics)]
7+
fn foo<T, const N: T>() {} // error!
8+
```
9+
10+
To fix this error, use a concrete type for the const parameter:
11+
12+
```
13+
#![feature(const_generics)]
14+
fn foo<T, const N: usize>() {}
15+
```

src/librustc_hir/hir.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2687,7 +2687,7 @@ pub enum Node<'hir> {
26872687
Crate(&'hir CrateItem<'hir>),
26882688
}
26892689

2690-
impl Node<'_> {
2690+
impl<'hir> Node<'hir> {
26912691
pub fn ident(&self) -> Option<Ident> {
26922692
match self {
26932693
Node::TraitItem(TraitItem { ident, .. })
@@ -2698,7 +2698,7 @@ impl Node<'_> {
26982698
}
26992699
}
27002700

2701-
pub fn fn_decl(&self) -> Option<&FnDecl<'_>> {
2701+
pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
27022702
match self {
27032703
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
27042704
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
@@ -2722,7 +2722,7 @@ impl Node<'_> {
27222722
}
27232723
}
27242724

2725-
pub fn generics(&self) -> Option<&Generics<'_>> {
2725+
pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
27262726
match self {
27272727
Node::TraitItem(TraitItem { generics, .. })
27282728
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),

src/librustc_resolve/diagnostics.rs

+13
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,19 @@ impl<'a> Resolver<'a> {
442442
);
443443
err
444444
}
445+
ResolutionError::ParamInTyOfConstArg(name) => {
446+
let mut err = struct_span_err!(
447+
self.session,
448+
span,
449+
E0770,
450+
"the type of const parameters must not depend on other generic parameters"
451+
);
452+
err.span_label(
453+
span,
454+
format!("the type must not depend on the parameter `{}`", name),
455+
);
456+
err
457+
}
445458
ResolutionError::SelfInTyParamDefault => {
446459
let mut err = struct_span_err!(
447460
self.session,

src/librustc_resolve/late.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ crate enum RibKind<'a> {
123123
/// from the default of a type parameter because they're not declared
124124
/// before said type parameter. Also see the `visit_generics` override.
125125
ForwardTyParamBanRibKind,
126+
127+
/// We are inside of the type of a const parameter. Can't refer to any
128+
/// parameters.
129+
ConstParamTyRibKind,
126130
}
127131

128132
impl RibKind<'_> {
@@ -135,7 +139,8 @@ impl RibKind<'_> {
135139
| FnItemRibKind
136140
| ConstantItemRibKind
137141
| ModuleRibKind(_)
138-
| MacroDefinition(_) => false,
142+
| MacroDefinition(_)
143+
| ConstParamTyRibKind => false,
139144
AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true,
140145
}
141146
}
@@ -576,7 +581,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
576581
for bound in &param.bounds {
577582
self.visit_param_bound(bound);
578583
}
584+
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
585+
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
579586
self.visit_ty(ty);
587+
self.ribs[TypeNS].pop().unwrap();
588+
self.ribs[ValueNS].pop().unwrap();
580589
}
581590
}
582591
}
@@ -814,7 +823,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
814823
| ItemRibKind(..)
815824
| ConstantItemRibKind
816825
| ModuleRibKind(..)
817-
| ForwardTyParamBanRibKind => {
826+
| ForwardTyParamBanRibKind
827+
| ConstParamTyRibKind => {
818828
return false;
819829
}
820830
}

src/librustc_resolve/lib.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ enum ResolutionError<'a> {
214214
BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
215215
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
216216
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
217+
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
218+
ParamInTyOfConstArg(Symbol),
217219
/// Error E0735: type parameters with a default cannot use `Self`
218220
SelfInTyParamDefault,
219221
/// Error E0767: use of unreachable label
@@ -2480,6 +2482,12 @@ impl<'a> Resolver<'a> {
24802482
}
24812483
return Res::Err;
24822484
}
2485+
ConstParamTyRibKind => {
2486+
if record_used {
2487+
self.report_error(span, ParamInTyOfConstArg(rib_ident.name));
2488+
}
2489+
return Res::Err;
2490+
}
24832491
}
24842492
}
24852493
if let Some(res_err) = res_err {
@@ -2503,6 +2511,15 @@ impl<'a> Resolver<'a> {
25032511
// This was an attempt to use a type parameter outside its scope.
25042512
ItemRibKind(has_generic_params) => has_generic_params,
25052513
FnItemRibKind => HasGenericParams::Yes,
2514+
ConstParamTyRibKind => {
2515+
if record_used {
2516+
self.report_error(
2517+
span,
2518+
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
2519+
);
2520+
}
2521+
return Res::Err;
2522+
}
25062523
};
25072524

25082525
if record_used {
@@ -2527,9 +2544,24 @@ impl<'a> Resolver<'a> {
25272544
}
25282545
for rib in ribs {
25292546
let has_generic_params = match rib.kind {
2547+
NormalRibKind
2548+
| ClosureOrAsyncRibKind
2549+
| AssocItemRibKind
2550+
| ModuleRibKind(..)
2551+
| MacroDefinition(..)
2552+
| ForwardTyParamBanRibKind
2553+
| ConstantItemRibKind => continue,
25302554
ItemRibKind(has_generic_params) => has_generic_params,
25312555
FnItemRibKind => HasGenericParams::Yes,
2532-
_ => continue,
2556+
ConstParamTyRibKind => {
2557+
if record_used {
2558+
self.report_error(
2559+
span,
2560+
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
2561+
);
2562+
}
2563+
return Res::Err;
2564+
}
25332565
};
25342566

25352567
// This was an attempt to use a const parameter outside its scope.

src/librustc_typeck/collect.rs

+56-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
2929
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
3030
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
3131
use rustc_hir::weak_lang_items;
32-
use rustc_hir::{GenericParamKind, Node};
32+
use rustc_hir::{GenericParamKind, HirId, Node};
3333
use rustc_middle::hir::map::blocks::FnLikeNode;
3434
use rustc_middle::hir::map::Map;
3535
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -1155,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
11551155
}
11561156
}
11571157

1158+
struct AnonConstInParamListDetector {
1159+
in_param_list: bool,
1160+
found_anon_const_in_list: bool,
1161+
ct: HirId,
1162+
}
1163+
1164+
impl<'v> Visitor<'v> for AnonConstInParamListDetector {
1165+
type Map = intravisit::ErasedMap<'v>;
1166+
1167+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
1168+
NestedVisitorMap::None
1169+
}
1170+
1171+
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
1172+
let prev = self.in_param_list;
1173+
self.in_param_list = true;
1174+
intravisit::walk_generic_param(self, p);
1175+
self.in_param_list = prev;
1176+
}
1177+
1178+
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
1179+
if self.in_param_list && self.ct == c.hir_id {
1180+
self.found_anon_const_in_list = true;
1181+
} else {
1182+
intravisit::walk_anon_const(self, c)
1183+
}
1184+
}
1185+
}
1186+
11581187
fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
11591188
use rustc_hir::*;
11601189

@@ -1176,10 +1205,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
11761205
let parent_id = tcx.hir().get_parent_item(hir_id);
11771206
let parent_def_id = tcx.hir().local_def_id(parent_id);
11781207

1179-
// HACK(eddyb) this provides the correct generics when
1180-
// `feature(const_generics)` is enabled, so that const expressions
1181-
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
1182-
if tcx.lazy_normalization() {
1208+
let mut in_param_list = false;
1209+
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
1210+
if let Some(generics) = node.generics() {
1211+
let mut visitor = AnonConstInParamListDetector {
1212+
in_param_list: false,
1213+
found_anon_const_in_list: false,
1214+
ct: hir_id,
1215+
};
1216+
1217+
visitor.visit_generics(generics);
1218+
in_param_list = visitor.found_anon_const_in_list;
1219+
break;
1220+
}
1221+
}
1222+
1223+
if in_param_list {
1224+
// We do not allow generic parameters in anon consts if we are inside
1225+
// of a param list.
1226+
//
1227+
// This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`,
1228+
// and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`.
1229+
None
1230+
} else if tcx.lazy_normalization() {
1231+
// HACK(eddyb) this provides the correct generics when
1232+
// `feature(const_generics)` is enabled, so that const expressions
1233+
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
11831234
Some(parent_def_id.to_def_id())
11841235
} else {
11851236
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(const_generics)]
2+
//~^ WARN the feature `const_generics` is incomplete
3+
4+
// Currently, const parameters cannot depend on other generic parameters,
5+
// as our current implementation can't really support this.
6+
//
7+
// We may want to lift this restriction in the future.
8+
9+
pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
10+
//~^ ERROR: the type of const parameters must not depend on other generic parameters
11+
12+
pub struct SelfDependent<const N: [u8; N]>;
13+
//~^ ERROR: the type of const parameters must not depend on other generic parameters
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0770]: the type of const parameters must not depend on other generic parameters
2+
--> $DIR/const-param-type-depends-on-const-param.rs:9:52
3+
|
4+
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
5+
| ^ the type must not depend on the parameter `N`
6+
7+
error[E0770]: the type of const parameters must not depend on other generic parameters
8+
--> $DIR/const-param-type-depends-on-const-param.rs:12:40
9+
|
10+
LL | pub struct SelfDependent<const N: [u8; N]>;
11+
| ^ the type must not depend on the parameter `N`
12+
13+
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
14+
--> $DIR/const-param-type-depends-on-const-param.rs:1:12
15+
|
16+
LL | #![feature(const_generics)]
17+
| ^^^^^^^^^^^^^^
18+
|
19+
= note: `#[warn(incomplete_features)]` on by default
20+
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
21+
22+
error: aborting due to 2 previous errors; 1 warning emitted
23+
24+
For more information about this error, try `rustc --explain E0770`.
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::marker::PhantomData;
22

33
struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
4-
//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
4+
//~^ ERROR the type of const parameters must not depend on other generic parameters
55

66
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error[E0770]: the type of const parameters must not depend on other generic parameters
2+
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
3+
|
4+
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
5+
| ^ the type must not depend on the parameter `T`
6+
17
error[E0658]: const generics are unstable
28
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
39
|
@@ -7,15 +13,7 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
713
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
814
= help: add `#![feature(const_generics)]` to the crate attributes to enable
915

10-
error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
11-
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
12-
|
13-
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
14-
| ^ `T` may not derive both `PartialEq` and `Eq`
15-
|
16-
= note: it is not currently possible to use a type parameter as the type of a const parameter
17-
1816
error: aborting due to 2 previous errors
1917

20-
Some errors have detailed explanations: E0658, E0741.
18+
Some errors have detailed explanations: E0658, E0770.
2119
For more information about an error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#![feature(const_generics)]
22
//~^ WARN the feature `const_generics` is incomplete
33

4-
// Currently, const parameters cannot depend on type parameters, because there is no way to
5-
// enforce the structural-match property on an arbitrary type parameter. This restriction
6-
// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more
7-
// details.
4+
// Currently, const parameters cannot depend on other generic parameters,
5+
// as our current implementation can't really support this.
6+
//
7+
// We may want to lift this restriction in the future.
88

99
pub struct Dependent<T, const X: T>([(); X]);
10-
//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
10+
//~^ ERROR: the type of const parameters must not depend on other generic parameters
11+
//~| ERROR: parameter `T` is never used
1112

1213
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error[E0770]: the type of const parameters must not depend on other generic parameters
2+
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
3+
|
4+
LL | pub struct Dependent<T, const X: T>([(); X]);
5+
| ^ the type must not depend on the parameter `T`
6+
17
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
28
--> $DIR/const-param-type-depends-on-type-param.rs:1:12
39
|
@@ -7,14 +13,15 @@ LL | #![feature(const_generics)]
713
= note: `#[warn(incomplete_features)]` on by default
814
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
915

10-
error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
11-
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
16+
error[E0392]: parameter `T` is never used
17+
--> $DIR/const-param-type-depends-on-type-param.rs:9:22
1218
|
1319
LL | pub struct Dependent<T, const X: T>([(); X]);
14-
| ^ `T` may not derive both `PartialEq` and `Eq`
20+
| ^ unused parameter
1521
|
16-
= note: it is not currently possible to use a type parameter as the type of a const parameter
22+
= help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
1723

18-
error: aborting due to previous error; 1 warning emitted
24+
error: aborting due to 2 previous errors; 1 warning emitted
1925

20-
For more information about this error, try `rustc --explain E0741`.
26+
Some errors have detailed explanations: E0392, E0770.
27+
For more information about an error, try `rustc --explain E0392`.

0 commit comments

Comments
 (0)