Skip to content

Commit 289e5fc

Browse files
committed
forbid generic params in complex consts
1 parent 375bccb commit 289e5fc

File tree

8 files changed

+194
-18
lines changed

8 files changed

+194
-18
lines changed

src/librustc_ast/ast.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,30 @@ impl Expr {
10521052
}
10531053
}
10541054

1055+
/// Is this expr either `N`, or `{ N }`.
1056+
///
1057+
/// If this is not the case, name resolution does not resolve `N` when using
1058+
/// `feature(min_const_generics)` as more complex expressions are not supported.
1059+
pub fn is_potential_trivial_const_param(&self) -> bool {
1060+
let this = if let ExprKind::Block(ref block, None) = self.kind {
1061+
if block.stmts.len() == 1 {
1062+
if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
1063+
} else {
1064+
self
1065+
}
1066+
} else {
1067+
self
1068+
};
1069+
1070+
if let ExprKind::Path(None, ref path) = this.kind {
1071+
if path.segments.len() == 1 && path.segments[0].args.is_none() {
1072+
return true;
1073+
}
1074+
}
1075+
1076+
false
1077+
}
1078+
10551079
pub fn to_bound(&self) -> Option<GenericBound> {
10561080
match &self.kind {
10571081
ExprKind::Path(None, path) => Some(GenericBound::Trait(

src/librustc_resolve/diagnostics.rs

+17
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,23 @@ impl<'a> Resolver<'a> {
466466
);
467467
err
468468
}
469+
ResolutionError::ParamInNonTrivialAnonConst(name) => {
470+
let mut err = self.session.struct_span_err(
471+
span,
472+
"generic parameters must not be used inside of non trivial constant values",
473+
);
474+
err.span_label(
475+
span,
476+
&format!(
477+
"non-trivial anonymous constants must not depend on the parameter `{}`",
478+
name
479+
),
480+
);
481+
err.help(
482+
&format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
483+
);
484+
err
485+
}
469486
ResolutionError::SelfInTyParamDefault => {
470487
let mut err = struct_span_err!(
471488
self.session,

src/librustc_resolve/late.rs

+29-15
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ crate enum RibKind<'a> {
111111
ItemRibKind(HasGenericParams),
112112

113113
/// We're in a constant item. Can't refer to dynamic stuff.
114-
ConstantItemRibKind,
114+
ConstantItemRibKind(bool),
115115

116116
/// We passed through a module.
117117
ModuleRibKind(Module<'a>),
@@ -137,7 +137,7 @@ impl RibKind<'_> {
137137
NormalRibKind
138138
| ClosureOrAsyncRibKind
139139
| FnItemRibKind
140-
| ConstantItemRibKind
140+
| ConstantItemRibKind(_)
141141
| ModuleRibKind(_)
142142
| MacroDefinition(_)
143143
| ConstParamTyRibKind => false,
@@ -426,7 +426,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
426426
}
427427
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
428428
debug!("visit_anon_const {:?}", constant);
429-
self.with_constant_rib(|this| {
429+
self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
430430
visit::walk_anon_const(this, constant);
431431
});
432432
}
@@ -628,7 +628,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
628628
if !check_ns(TypeNS) && check_ns(ValueNS) {
629629
// This must be equivalent to `visit_anon_const`, but we cannot call it
630630
// directly due to visitor lifetimes so we have to copy-paste some code.
631-
self.with_constant_rib(|this| {
631+
self.with_constant_rib(true, |this| {
632632
this.smart_resolve_path(
633633
ty.id,
634634
qself.as_ref(),
@@ -829,7 +829,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
829829
| ClosureOrAsyncRibKind
830830
| FnItemRibKind
831831
| ItemRibKind(..)
832-
| ConstantItemRibKind
832+
| ConstantItemRibKind(_)
833833
| ModuleRibKind(..)
834834
| ForwardTyParamBanRibKind
835835
| ConstParamTyRibKind => {
@@ -948,7 +948,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
948948
// Only impose the restrictions of `ConstRibKind` for an
949949
// actual constant expression in a provided default.
950950
if let Some(expr) = default {
951-
this.with_constant_rib(|this| this.visit_expr(expr));
951+
this.with_constant_rib(
952+
expr.is_potential_trivial_const_param(),
953+
|this| this.visit_expr(expr),
954+
);
952955
}
953956
}
954957
AssocItemKind::Fn(_, _, generics, _) => {
@@ -989,7 +992,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
989992
self.with_item_rib(HasGenericParams::No, |this| {
990993
this.visit_ty(ty);
991994
if let Some(expr) = expr {
992-
this.with_constant_rib(|this| this.visit_expr(expr));
995+
this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
996+
this.visit_expr(expr)
997+
});
993998
}
994999
});
9951000
}
@@ -1086,11 +1091,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
10861091
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
10871092
}
10881093

1089-
fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
1094+
fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
10901095
debug!("with_constant_rib");
1091-
self.with_rib(ValueNS, ConstantItemRibKind, |this| {
1092-
this.with_rib(TypeNS, ConstantItemRibKind, |this| {
1093-
this.with_label_rib(ConstantItemRibKind, f);
1096+
self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
1097+
this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
1098+
this.with_label_rib(ConstantItemRibKind(trivial), f);
10941099
})
10951100
});
10961101
}
@@ -1220,7 +1225,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12201225
for item in impl_items {
12211226
use crate::ResolutionError::*;
12221227
match &item.kind {
1223-
AssocItemKind::Const(..) => {
1228+
AssocItemKind::Const(_default, _ty, expr) => {
12241229
debug!("resolve_implementation AssocItemKind::Const",);
12251230
// If this is a trait impl, ensure the const
12261231
// exists in trait
@@ -1231,9 +1236,18 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12311236
|n, s| ConstNotMemberOfTrait(n, s),
12321237
);
12331238

1234-
this.with_constant_rib(|this| {
1235-
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
1236-
});
1239+
this.with_constant_rib(
1240+
expr.as_ref().map_or(false, |e| {
1241+
e.is_potential_trivial_const_param()
1242+
}),
1243+
|this| {
1244+
visit::walk_assoc_item(
1245+
this,
1246+
item,
1247+
AssocCtxt::Impl,
1248+
)
1249+
},
1250+
);
12371251
}
12381252
AssocItemKind::Fn(_, _, generics, _) => {
12391253
// We also need a new scope for the impl item type parameters.

src/librustc_resolve/lib.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ enum ResolutionError<'a> {
218218
ParamInTyOfConstParam(Symbol),
219219
/// constant values inside of type parameter defaults must not depend on generic parameters.
220220
ParamInAnonConstInTyDefault(Symbol),
221+
/// generic parameters must not be used inside of non trivial constant values.
222+
///
223+
/// This error is only emitted when using `min_const_generics`.
224+
ParamInNonTrivialAnonConst(Symbol),
221225
/// Error E0735: type parameters with a default cannot use `Self`
222226
SelfInTyParamDefault,
223227
/// Error E0767: use of unreachable label
@@ -2507,7 +2511,7 @@ impl<'a> Resolver<'a> {
25072511
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
25082512
}
25092513
}
2510-
ConstantItemRibKind => {
2514+
ConstantItemRibKind(_) => {
25112515
// Still doesn't deal with upvars
25122516
if record_used {
25132517
self.report_error(span, AttemptToUseNonConstantValueInConstant);
@@ -2546,7 +2550,18 @@ impl<'a> Resolver<'a> {
25462550
in_ty_param_default = true;
25472551
continue;
25482552
}
2549-
ConstantItemRibKind => {
2553+
ConstantItemRibKind(trivial) => {
2554+
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
2555+
if !trivial && self.session.features_untracked().min_const_generics {
2556+
if record_used {
2557+
self.report_error(
2558+
span,
2559+
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
2560+
);
2561+
}
2562+
return Res::Err;
2563+
}
2564+
25502565
if in_ty_param_default {
25512566
if record_used {
25522567
self.report_error(
@@ -2612,7 +2627,18 @@ impl<'a> Resolver<'a> {
26122627
in_ty_param_default = true;
26132628
continue;
26142629
}
2615-
ConstantItemRibKind => {
2630+
ConstantItemRibKind(trivial) => {
2631+
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
2632+
if !trivial && self.session.features_untracked().min_const_generics {
2633+
if record_used {
2634+
self.report_error(
2635+
span,
2636+
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
2637+
);
2638+
}
2639+
return Res::Err;
2640+
}
2641+
26162642
if in_ty_param_default {
26172643
if record_used {
26182644
self.report_error(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![feature(min_const_generics)]
2+
3+
fn test<const N: usize>() {}
4+
5+
fn ok<const M: usize>() -> [u8; M] {
6+
[0; { M }]
7+
}
8+
9+
struct Break0<const N: usize>([u8; { N + 1 }]);
10+
//~^ ERROR generic parameters must not be used inside of non trivial constant values
11+
12+
struct Break1<const N: usize>([u8; { { N } }]);
13+
//~^ ERROR generic parameters must not be used inside of non trivial constant values
14+
15+
fn break2<const N: usize>() {
16+
let _: [u8; N + 1];
17+
//~^ ERROR generic parameters must not be used inside of non trivial constant values
18+
}
19+
20+
fn break3<const N: usize>() {
21+
let _ = [0; N + 1];
22+
//~^ ERROR generic parameters must not be used inside of non trivial constant values
23+
}
24+
25+
trait Foo {
26+
const ASSOC: usize;
27+
}
28+
29+
impl<const N: usize> Foo for [u8; N] {
30+
const ASSOC: usize = N + 1;
31+
//~^ ERROR generic parameters must not be used inside of non trivial constant values
32+
// FIXME(min_const_generics): We probably have to allow this as we can
33+
// already allow referencing type parameters here on stable.
34+
}
35+
36+
37+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
error: generic parameters must not be used inside of non trivial constant values
2+
--> $DIR/complex-expression.rs:9:38
3+
|
4+
LL | struct Break0<const N: usize>([u8; { N + 1 }]);
5+
| ^ non-trivial anonymous constants must not depend on the parameter `N`
6+
|
7+
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
8+
9+
error: generic parameters must not be used inside of non trivial constant values
10+
--> $DIR/complex-expression.rs:12:40
11+
|
12+
LL | struct Break1<const N: usize>([u8; { { N } }]);
13+
| ^ non-trivial anonymous constants must not depend on the parameter `N`
14+
|
15+
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
16+
17+
error: generic parameters must not be used inside of non trivial constant values
18+
--> $DIR/complex-expression.rs:16:17
19+
|
20+
LL | let _: [u8; N + 1];
21+
| ^ non-trivial anonymous constants must not depend on the parameter `N`
22+
|
23+
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
24+
25+
error: generic parameters must not be used inside of non trivial constant values
26+
--> $DIR/complex-expression.rs:21:17
27+
|
28+
LL | let _ = [0; N + 1];
29+
| ^ non-trivial anonymous constants must not depend on the parameter `N`
30+
|
31+
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
32+
33+
error: generic parameters must not be used inside of non trivial constant values
34+
--> $DIR/complex-expression.rs:30:26
35+
|
36+
LL | const ASSOC: usize = N + 1;
37+
| ^ non-trivial anonymous constants must not depend on the parameter `N`
38+
|
39+
= help: it is currently only allowed to use either `N` or `{ N }` as generic constants
40+
41+
error: aborting due to 5 previous errors
42+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn test<const N: usize>() {}
2+
//~^ ERROR const generics are unstable
3+
4+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: const generics are unstable
2+
--> $DIR/feature-gate-min_const_generics.rs:1:15
3+
|
4+
LL | fn test<const N: usize>() {}
5+
| ^
6+
|
7+
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
8+
= help: add `#![feature(const_generics)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)