Skip to content

Commit 0fb4380

Browse files
committed
Auto merge of #67667 - wesleywiser:speed_up_trivially_valid_constants, r=oli-obk
Resolve long compile times when evaluating always valid constants This extends the existing logic which skips validating every integer or floating point number type to also skip validating empty structs because they are also trivially valid. Fixes #67539 r? @oli-obk cc @RalfJung @spastorino
2 parents 580ac0b + 5ca3a1b commit 0fb4380

File tree

4 files changed

+99
-3
lines changed

4 files changed

+99
-3
lines changed

src/librustc_mir/interpret/validity.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -580,10 +580,19 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
580580
}
581581
ty::Array(tys, ..) | ty::Slice(tys)
582582
if {
583-
// This optimization applies only for integer and floating point types
584-
// (i.e., types that can hold arbitrary bytes).
583+
// This optimization applies for types that can hold arbitrary bytes (such as
584+
// integer and floating point types) or for structs or tuples with no fields.
585+
// FIXME(wesleywiser) This logic could be extended further to arbitrary structs
586+
// or tuples made up of integer/floating point types or inhabited ZSTs with no
587+
// padding.
585588
match tys.kind {
586589
ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
590+
ty::Tuple(tys) if tys.len() == 0 => true,
591+
ty::Adt(adt_def, _)
592+
if adt_def.is_struct() && adt_def.all_fields().next().is_none() =>
593+
{
594+
true
595+
}
587596
_ => false,
588597
}
589598
} =>
@@ -609,7 +618,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
609618
// Size is not 0, get a pointer.
610619
let ptr = self.ecx.force_ptr(mplace.ptr)?;
611620

612-
// This is the optimization: we just check the entire range at once.
621+
// Optimization: we just check the entire range at once.
613622
// NOTE: Keep this in sync with the handling of integer and float
614623
// types above, in `visit_primitive`.
615624
// In run-time mode, we accept pointers in here. This is actually more
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(const_fn)]
2+
#![feature(const_transmute)]
3+
4+
const fn foo() -> ! {
5+
unsafe { std::mem::transmute(()) }
6+
//~^ WARN any use of this value will cause an error [const_err]
7+
//~| WARN the type `!` does not permit zero-initialization [invalid_value]
8+
}
9+
10+
#[derive(Clone, Copy)]
11+
enum Empty { }
12+
13+
#[warn(const_err)]
14+
const FOO: [Empty; 3] = [foo(); 3];
15+
16+
#[warn(const_err)]
17+
const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
18+
//~^ ERROR it is undefined behavior to use this value
19+
//~| WARN the type `Empty` does not permit zero-initialization
20+
21+
fn main() {
22+
FOO;
23+
BAR;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
warning: any use of this value will cause an error
2+
--> $DIR/validate_uninhabited_zsts.rs:5:14
3+
|
4+
LL | unsafe { std::mem::transmute(()) }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| entering unreachable code
8+
| inside call to `foo` at $DIR/validate_uninhabited_zsts.rs:14:26
9+
...
10+
LL | const FOO: [Empty; 3] = [foo(); 3];
11+
| -----------------------------------
12+
|
13+
note: lint level defined here
14+
--> $DIR/validate_uninhabited_zsts.rs:13:8
15+
|
16+
LL | #[warn(const_err)]
17+
| ^^^^^^^^^
18+
19+
error[E0080]: it is undefined behavior to use this value
20+
--> $DIR/validate_uninhabited_zsts.rs:17:1
21+
|
22+
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
24+
|
25+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
26+
27+
warning: the type `!` does not permit zero-initialization
28+
--> $DIR/validate_uninhabited_zsts.rs:5:14
29+
|
30+
LL | unsafe { std::mem::transmute(()) }
31+
| ^^^^^^^^^^^^^^^^^^^^^^^
32+
| |
33+
| this code causes undefined behavior when executed
34+
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
35+
|
36+
= note: `#[warn(invalid_value)]` on by default
37+
= note: The never type (`!`) has no valid value
38+
39+
warning: the type `Empty` does not permit zero-initialization
40+
--> $DIR/validate_uninhabited_zsts.rs:17:35
41+
|
42+
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
43+
| ^^^^^^^^^^^^^^^^^^^^^^^
44+
| |
45+
| this code causes undefined behavior when executed
46+
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
47+
|
48+
= note: 0-variant enums have no valid value
49+
50+
error: aborting due to previous error
51+
52+
For more information about this error, try `rustc --explain E0080`.

src/test/ui/consts/huge-values.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// build-pass
2+
// ignore-32bit
3+
4+
#[derive(Clone, Copy)]
5+
struct Foo;
6+
7+
fn main() {
8+
let _ = [(); 4_000_000_000];
9+
let _ = [0u8; 4_000_000_000];
10+
let _ = [Foo; 4_000_000_000];
11+
}

0 commit comments

Comments
 (0)