Skip to content

Commit 4a15a25

Browse files
committed
min_const_generics: allow ty param in repeat expr
1 parent 8f0fa9d commit 4a15a25

File tree

9 files changed

+192
-38
lines changed

9 files changed

+192
-38
lines changed

Diff for: compiler/rustc_resolve/src/late.rs

+70-18
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ enum PatternSource {
5757
FnParam,
5858
}
5959

60+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
61+
enum IsRepeatExpr {
62+
No,
63+
Yes,
64+
}
65+
6066
impl PatternSource {
6167
fn descr(self) -> &'static str {
6268
match self {
@@ -437,10 +443,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
437443
self.resolve_block(block);
438444
}
439445
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
440-
debug!("visit_anon_const {:?}", constant);
441-
self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
442-
visit::walk_anon_const(this, constant);
443-
});
446+
// We deal with repeat expressions explicitly in `resolve_expr`.
447+
self.resolve_anon_const(constant, IsRepeatExpr::No);
444448
}
445449
fn visit_expr(&mut self, expr: &'ast Expr) {
446450
self.resolve_expr(expr, None);
@@ -647,7 +651,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
647651
if !check_ns(TypeNS) && check_ns(ValueNS) {
648652
// This must be equivalent to `visit_anon_const`, but we cannot call it
649653
// directly due to visitor lifetimes so we have to copy-paste some code.
650-
self.with_constant_rib(true, |this| {
654+
//
655+
// Note that we might not be inside of an repeat expression here,
656+
// but considering that `IsRepeatExpr` is only relevant for
657+
// non-trivial constants this is doesn't matter.
658+
self.with_constant_rib(IsRepeatExpr::No, true, |this| {
651659
this.smart_resolve_path(
652660
ty.id,
653661
qself.as_ref(),
@@ -980,9 +988,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
980988
//
981989
// Type parameters can already be used and as associated consts are
982990
// not used as part of the type system, this is far less surprising.
983-
this.with_constant_rib(true, |this| {
984-
this.visit_expr(expr)
985-
});
991+
this.with_constant_rib(
992+
IsRepeatExpr::No,
993+
true,
994+
|this| this.visit_expr(expr),
995+
);
986996
}
987997
}
988998
AssocItemKind::Fn(_, _, generics, _) => {
@@ -1023,7 +1033,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
10231033
self.with_item_rib(HasGenericParams::No, |this| {
10241034
this.visit_ty(ty);
10251035
if let Some(expr) = expr {
1026-
this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
1036+
// We already forbid generic params because of the above item rib,
1037+
// so it doesn't matter whether this is a trivial constant.
1038+
this.with_constant_rib(IsRepeatExpr::No, true, |this| {
10271039
this.visit_expr(expr)
10281040
});
10291041
}
@@ -1122,12 +1134,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
11221134
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
11231135
}
11241136

1125-
fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
1126-
debug!("with_constant_rib");
1127-
self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
1128-
this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
1129-
this.with_label_rib(ConstantItemRibKind(trivial), f);
1130-
})
1137+
// HACK(min_const_generics,const_evaluatable_unchecked): We
1138+
// want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
1139+
// with a future compat lint for now. We do this by adding an
1140+
// additional special case for repeat expressions.
1141+
//
1142+
// Note that we intentionally still forbid `[0; N + 1]` during
1143+
// name resolution so that we don't extend the future
1144+
// compat lint to new cases.
1145+
fn with_constant_rib(
1146+
&mut self,
1147+
is_repeat: IsRepeatExpr,
1148+
is_trivial: bool,
1149+
f: impl FnOnce(&mut Self),
1150+
) {
1151+
debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
1152+
self.with_rib(ValueNS, ConstantItemRibKind(is_trivial), |this| {
1153+
this.with_rib(
1154+
TypeNS,
1155+
ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial),
1156+
|this| {
1157+
this.with_label_rib(ConstantItemRibKind(is_trivial), f);
1158+
},
1159+
)
11311160
});
11321161
}
11331162

@@ -1272,9 +1301,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12721301
//
12731302
// Type parameters can already be used and as associated consts are
12741303
// not used as part of the type system, this is far less surprising.
1275-
this.with_constant_rib(true, |this| {
1276-
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
1277-
});
1304+
this.with_constant_rib(
1305+
IsRepeatExpr::No,
1306+
true,
1307+
|this| {
1308+
visit::walk_assoc_item(
1309+
this,
1310+
item,
1311+
AssocCtxt::Impl,
1312+
)
1313+
},
1314+
);
12781315
}
12791316
AssocItemKind::Fn(_, _, generics, _) => {
12801317
// We also need a new scope for the impl item type parameters.
@@ -2199,6 +2236,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
21992236
debug!("(resolving block) leaving block");
22002237
}
22012238

2239+
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) {
2240+
debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
2241+
self.with_constant_rib(
2242+
is_repeat,
2243+
constant.value.is_potential_trivial_const_param(),
2244+
|this| {
2245+
visit::walk_anon_const(this, constant);
2246+
},
2247+
);
2248+
}
2249+
22022250
fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
22032251
// First, record candidate traits for this expression if it could
22042252
// result in the invocation of a method call.
@@ -2322,6 +2370,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
23222370
ExprKind::Async(..) | ExprKind::Closure(..) => {
23232371
self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
23242372
}
2373+
ExprKind::Repeat(ref elem, ref ct) => {
2374+
self.visit_expr(elem);
2375+
self.resolve_anon_const(ct, IsRepeatExpr::Yes);
2376+
}
23252377
_ => {
23262378
visit::walk_expr(self, expr);
23272379
}
+13-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
error: generic `Self` types are currently not permitted in anonymous constants
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-62504.rs:19:21
3+
|
4+
LL | ArrayHolder([0; Self::SIZE])
5+
| ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
6+
|
7+
= note: expected array `[u32; X]`
8+
found array `[u32; _]`
9+
10+
error: constant expression depends on a generic parameter
211
--> $DIR/issue-62504.rs:19:25
312
|
413
LL | ArrayHolder([0; Self::SIZE])
514
| ^^^^^^^^^^
615
|
7-
note: not a concrete type
8-
--> $DIR/issue-62504.rs:17:22
9-
|
10-
LL | impl<const X: usize> ArrayHolder<X> {
11-
| ^^^^^^^^^^^^^^
16+
= note: this may fail depending on what value the parameter takes
1217

13-
error: aborting due to previous error
18+
error: aborting due to 2 previous errors
1419

20+
For more information about this error, try `rustc --explain E0308`.

Diff for: src/test/ui/const-generics/issues/issue-62504.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ struct ArrayHolder<const X: usize>([u32; X]);
1717
impl<const X: usize> ArrayHolder<X> {
1818
pub const fn new() -> Self {
1919
ArrayHolder([0; Self::SIZE])
20-
//[full]~^ ERROR constant expression depends on a generic parameter
21-
//[min]~^^ ERROR generic `Self` types are currently
20+
//~^ ERROR constant expression depends on a generic parameter
21+
//[min]~| ERROR mismatched types
2222
}
2323
}
2424

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: generic parameters may not be used in const operations
2-
--> $DIR/issue-67739.rs:12:30
1+
error: constant expression depends on a generic parameter
2+
--> $DIR/issue-67739.rs:12:15
33
|
44
LL | [0u8; mem::size_of::<Self::Associated>()];
5-
| ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: type parameters may not be used in const expressions
7+
= note: this may fail depending on what value the parameter takes
88

99
error: aborting due to previous error
1010

Diff for: src/test/ui/const-generics/issues/issue-67739.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ pub trait Trait {
1010

1111
fn associated_size(&self) -> usize {
1212
[0u8; mem::size_of::<Self::Associated>()];
13-
//[full]~^ ERROR constant expression depends on a generic parameter
14-
//[min]~^^ ERROR generic parameters may not be used in const operations
13+
//~^ ERROR constant expression depends on a generic parameter
1514
0
1615
}
1716
}

Diff for: src/test/ui/const-generics/min_const_generics/complex-expression.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#![feature(min_const_generics)]
22

3+
use std::mem::size_of;
4+
35
fn test<const N: usize>() {}
46

57
fn ok<const M: usize>() -> [u8; M] {
@@ -22,6 +24,24 @@ fn break3<const N: usize>() {
2224
//~^ ERROR generic parameters may not be used in const operations
2325
}
2426

27+
struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
28+
//~^ ERROR generic parameters may not be used in const operations
29+
30+
struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
31+
//~^ ERROR generic parameters may not be used in const operations
32+
33+
fn break_ty2<T>() {
34+
let _: [u8; size_of::<*mut T>() + 1];
35+
//~^ ERROR generic parameters may not be used in const operations
36+
}
37+
38+
fn break_ty3<T>() {
39+
let _ = [0; size_of::<*mut T>() + 1];
40+
//~^ WARN cannot use constants which depend on generic parameters in types
41+
//~| WARN this was previously accepted by the compiler but is being phased out
42+
}
43+
44+
2545
trait Foo {
2646
const ASSOC: usize;
2747
}
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,68 @@
11
error: generic parameters may not be used in const operations
2-
--> $DIR/complex-expression.rs:9:38
2+
--> $DIR/complex-expression.rs:11:38
33
|
44
LL | struct Break0<const N: usize>([u8; { N + 1 }]);
55
| ^ cannot perform const operation using `N`
66
|
77
= help: const parameters may only be used as standalone arguments, i.e. `N`
88

99
error: generic parameters may not be used in const operations
10-
--> $DIR/complex-expression.rs:12:40
10+
--> $DIR/complex-expression.rs:14:40
1111
|
1212
LL | struct Break1<const N: usize>([u8; { { N } }]);
1313
| ^ cannot perform const operation using `N`
1414
|
1515
= help: const parameters may only be used as standalone arguments, i.e. `N`
1616

1717
error: generic parameters may not be used in const operations
18-
--> $DIR/complex-expression.rs:16:17
18+
--> $DIR/complex-expression.rs:18:17
1919
|
2020
LL | let _: [u8; N + 1];
2121
| ^ cannot perform const operation using `N`
2222
|
2323
= help: const parameters may only be used as standalone arguments, i.e. `N`
2424

2525
error: generic parameters may not be used in const operations
26-
--> $DIR/complex-expression.rs:21:17
26+
--> $DIR/complex-expression.rs:23:17
2727
|
2828
LL | let _ = [0; N + 1];
2929
| ^ cannot perform const operation using `N`
3030
|
3131
= help: const parameters may only be used as standalone arguments, i.e. `N`
3232

33-
error: aborting due to 4 previous errors
33+
error: generic parameters may not be used in const operations
34+
--> $DIR/complex-expression.rs:27:45
35+
|
36+
LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
37+
| ^ cannot perform const operation using `T`
38+
|
39+
= note: type parameters may not be used in const expressions
40+
41+
error: generic parameters may not be used in const operations
42+
--> $DIR/complex-expression.rs:30:47
43+
|
44+
LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
45+
| ^ cannot perform const operation using `T`
46+
|
47+
= note: type parameters may not be used in const expressions
48+
49+
error: generic parameters may not be used in const operations
50+
--> $DIR/complex-expression.rs:34:32
51+
|
52+
LL | let _: [u8; size_of::<*mut T>() + 1];
53+
| ^ cannot perform const operation using `T`
54+
|
55+
= note: type parameters may not be used in const expressions
56+
57+
warning: cannot use constants which depend on generic parameters in types
58+
--> $DIR/complex-expression.rs:39:17
59+
|
60+
LL | let _ = [0; size_of::<*mut T>() + 1];
61+
| ^^^^^^^^^^^^^^^^^^^^^^^
62+
|
63+
= note: `#[warn(const_evaluatable_unchecked)]` on by default
64+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
65+
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
66+
67+
error: aborting due to 7 previous errors; 1 warning emitted
3468

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
#![allow(dead_code)]
3+
4+
fn foo<T>() {
5+
[0; std::mem::size_of::<*mut T>()];
6+
//~^ WARN cannot use constants which depend on generic parameters in types
7+
//~| WARN this was previously accepted by the compiler but is being phased out
8+
}
9+
10+
struct Foo<T>(T);
11+
12+
impl<T> Foo<T> {
13+
const ASSOC: usize = 4;
14+
15+
fn test() {
16+
[0; Self::ASSOC];
17+
//~^ WARN cannot use constants which depend on generic parameters in types
18+
//~| WARN this was previously accepted by the compiler but is being phased out
19+
}
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
warning: cannot use constants which depend on generic parameters in types
2+
--> $DIR/const-evaluatable-unchecked.rs:5:9
3+
|
4+
LL | [0; std::mem::size_of::<*mut T>()];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(const_evaluatable_unchecked)]` on by default
8+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
9+
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
10+
11+
warning: cannot use constants which depend on generic parameters in types
12+
--> $DIR/const-evaluatable-unchecked.rs:16:13
13+
|
14+
LL | [0; Self::ASSOC];
15+
| ^^^^^^^^^^^
16+
|
17+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
18+
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
19+
20+
warning: 2 warnings emitted
21+

0 commit comments

Comments
 (0)