Skip to content

Commit d4a0dd9

Browse files
Rollup merge of rust-lang#96557 - nbdd0121:const, r=oli-obk
Allow inline consts to reference generic params Tracking issue: rust-lang#76001 The RFC says that inline consts cannot reference to generic parameters (for now), same as array length expressions. And expresses that it's desirable for it to reference in-scope generics, when array length expressions gain that feature as well. However it is possible to implement this for inline consts before doing this for all anon consts, because inline consts are only used as values and they won't be used in the type system. So we can have: ```rust fn foo<T>() { let x = [4i32; std::mem::size_of::<T>()]; // NOT ALLOWED (for now) let x = const { std::mem::size_of::<T>() }; // ALLOWED with this PR! let x = [4i32; const { std::mem::size_of::<T>() }]; // NOT ALLOWED (for now) } ``` This would make inline consts super useful for compile-time checks and assertions: ```rust fn assert_zst<T>() { const { assert!(std::mem::size_of::<T>() == 0) }; } ``` This would create an error during monomorphization when `assert_zst` is instantiated with non-ZST `T`s. A error during mono might sound scary, but this is exactly what a "desugared" inline const would do: ```rust fn assert_zst<T>() { struct F<T>(T); impl<T> F<T> { const V: () = assert!(std::mem::size_of::<T>() == 0); } let _ = F::<T>::V; } ``` It should also be noted that the current inline const implementation can already reference the type params via type inference, so this resolver-level restriction is not any useful either: ```rust fn foo<T>() -> usize { let (_, size): (PhantomData<T>, usize) = const { const fn my_size_of<T>() -> (PhantomData<T>, usize) { (PhantomData, std::mem::size_of::<T>()) } my_size_of() }; size } ``` ``@rustbot`` label: F-inline_const
2 parents 9ac8200 + 5b5ac28 commit d4a0dd9

10 files changed

+96
-7
lines changed

compiler/rustc_middle/src/ty/print/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ pub trait Printer<'tcx>: Sized {
136136
match key.disambiguated_data.data {
137137
// Closures' own generics are only captures, don't print them.
138138
DefPathData::ClosureExpr => {}
139+
// This covers both `DefKind::AnonConst` and `DefKind::InlineConst`.
140+
// Anon consts doesn't have their own generics, and inline consts' own
141+
// generics are their inferred types, so don't print them.
142+
DefPathData::AnonConst => {}
139143

140144
// If we have any generic arguments to print, we do that
141145
// on top of the same path, but without its own generics.

compiler/rustc_resolve/src/late.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -3105,6 +3105,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
31053105
);
31063106
}
31073107

3108+
fn resolve_inline_const(&mut self, constant: &'ast AnonConst) {
3109+
debug!("resolve_anon_const {constant:?}");
3110+
self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
3111+
visit::walk_anon_const(this, constant);
3112+
});
3113+
}
3114+
31083115
fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
31093116
// First, record candidate traits for this expression if it could
31103117
// result in the invocation of a method call.
@@ -3261,7 +3268,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
32613268
});
32623269
}
32633270
ExprKind::ConstBlock(ref ct) => {
3264-
self.resolve_anon_const(ct, IsRepeatExpr::No);
3271+
self.resolve_inline_const(ct);
32653272
}
32663273
ExprKind::Index(ref elem, ref idx) => {
32673274
self.resolve_expr(elem, Some(expr));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// build-fail
2+
#![feature(inline_const)]
3+
4+
fn foo<T>() {
5+
const { assert!(std::mem::size_of::<T>() == 0); } //~ ERROR E0080
6+
}
7+
8+
fn bar<const N: usize>() -> usize {
9+
const { N - 1 } //~ ERROR E0080
10+
}
11+
12+
fn main() {
13+
foo::<i32>();
14+
bar::<0>();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0080]: evaluation of `foo::<i32>::{constant#0}` failed
2+
--> $DIR/const-expr-generic-err.rs:5:13
3+
|
4+
LL | const { assert!(std::mem::size_of::<T>() == 0); }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::<T>() == 0', $DIR/const-expr-generic-err.rs:5:13
6+
|
7+
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: the above error was encountered while instantiating `fn foo::<i32>`
10+
--> $DIR/const-expr-generic-err.rs:13:5
11+
|
12+
LL | foo::<i32>();
13+
| ^^^^^^^^^^^^
14+
15+
error[E0080]: evaluation of `bar::<0_usize>::{constant#0}` failed
16+
--> $DIR/const-expr-generic-err.rs:9:13
17+
|
18+
LL | const { N - 1 }
19+
| ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
20+
21+
note: the above error was encountered while instantiating `fn bar::<0_usize>`
22+
--> $DIR/const-expr-generic-err.rs:14:5
23+
|
24+
LL | bar::<0>();
25+
| ^^^^^^^^^^
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(inline_const)]
2+
3+
fn foo<T>() {
4+
let _ = [0u8; const { std::mem::size_of::<T>() }];
5+
//~^ ERROR: constant expression depends on a generic parameter
6+
}
7+
8+
fn main() {
9+
foo::<i32>();
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: constant expression depends on a generic parameter
2+
--> $DIR/const-expr-generic-err2.rs:4:19
3+
|
4+
LL | let _ = [0u8; const { std::mem::size_of::<T>() }];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: this may fail depending on what value the parameter takes
8+
9+
error: aborting due to previous error
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// check-pass
2+
#![feature(inline_const)]
3+
4+
fn foo<T>() -> usize {
5+
const { std::mem::size_of::<T>() }
6+
}
7+
8+
fn bar<const N: usize>() -> usize {
9+
const { N + 1 }
10+
}
11+
12+
fn main() {
13+
foo::<i32>();
14+
bar::<1>();
15+
}

src/test/ui/inline-const/const-match-pat-generic.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![allow(incomplete_features)]
22
#![feature(inline_const_pat)]
3-
#![feature(generic_const_exprs)]
43

54
// rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter
65

@@ -16,7 +15,7 @@ const fn f(x: usize) -> usize {
1615
x + 1
1716
}
1817

19-
fn bar<const V: usize>() where [(); f(V)]: {
18+
fn bar<const V: usize>() {
2019
match 0 {
2120
const { f(V) } => {},
2221
//~^ ERROR constant pattern depends on a generic parameter

src/test/ui/inline-const/const-match-pat-generic.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
error[E0158]: const parameters cannot be referenced in patterns
2-
--> $DIR/const-match-pat-generic.rs:9:9
2+
--> $DIR/const-match-pat-generic.rs:8:9
33
|
44
LL | const { V } => {},
55
| ^^^^^^^^^^^
66

77
error: constant pattern depends on a generic parameter
8-
--> $DIR/const-match-pat-generic.rs:21:9
8+
--> $DIR/const-match-pat-generic.rs:20:9
99
|
1010
LL | const { f(V) } => {},
1111
| ^^^^^^^^^^^^^^
1212

1313
error: constant pattern depends on a generic parameter
14-
--> $DIR/const-match-pat-generic.rs:21:9
14+
--> $DIR/const-match-pat-generic.rs:20:9
1515
|
1616
LL | const { f(V) } => {},
1717
| ^^^^^^^^^^^^^^

src/tools/clippy/tests/ui/indexing_slicing_index.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0080]: evaluation of `main::{constant#3}::<&i32>` failed
1+
error[E0080]: evaluation of `main::{constant#3}` failed
22
--> $DIR/indexing_slicing_index.rs:31:14
33
|
44
LL | const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.

0 commit comments

Comments
 (0)