Skip to content

Commit eda88a3

Browse files
authored
Rollup merge of #109435 - oli-obk:🇨🇭🥚_copy_op, r=RalfJung
Detect uninhabited types early in const eval r? `@RalfJung` implements #108442 (comment) this is a breaking change, as some UB during const eval is now detected instead of silently being ignored. Users can see this and other UB that may cause future breakage with `-Zextra-const-ub-checks` or just by running miri on their code, which sets that flag by default.
2 parents 031640c + f066d67 commit eda88a3

13 files changed

+38
-38
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_hir::def::DefKind;
22
use rustc_hir::{LangItem, CRATE_HIR_ID};
33
use rustc_middle::mir;
44
use rustc_middle::mir::interpret::PointerArithmetic;
5-
use rustc_middle::ty::layout::FnAbiOf;
5+
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
66
use rustc_middle::ty::{self, Ty, TyCtxt};
77
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
88
use std::borrow::Borrow;
@@ -335,8 +335,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
335335
}
336336

337337
#[inline(always)]
338-
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
339-
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
338+
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
339+
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
340340
}
341341

342342
fn alignment_check_failed(

compiler/rustc_const_eval/src/interpret/machine.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::hash::Hash;
88

99
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1010
use rustc_middle::mir;
11+
use rustc_middle::ty::layout::TyAndLayout;
1112
use rustc_middle::ty::{self, Ty, TyCtxt};
1213
use rustc_span::def_id::DefId;
1314
use rustc_target::abi::{Align, Size};
@@ -145,8 +146,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
145146
check: CheckAlignment,
146147
) -> InterpResult<'tcx, ()>;
147148

148-
/// Whether to enforce the validity invariant
149-
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
149+
/// Whether to enforce the validity invariant for a specific layout.
150+
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;
150151

151152
/// Whether function calls should be [ABI](CallAbi)-checked.
152153
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {

compiler/rustc_const_eval/src/interpret/place.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ where
461461
) -> InterpResult<'tcx> {
462462
self.write_immediate_no_validate(src, dest)?;
463463

464-
if M::enforce_validity(self) {
464+
if M::enforce_validity(self, dest.layout) {
465465
// Data got changed, better make sure it matches the type!
466466
self.validate_operand(&self.place_to_op(dest)?)?;
467467
}
@@ -616,7 +616,7 @@ where
616616
) -> InterpResult<'tcx> {
617617
self.copy_op_no_validate(src, dest, allow_transmute)?;
618618

619-
if M::enforce_validity(self) {
619+
if M::enforce_validity(self, dest.layout) {
620620
// Data got changed, better make sure it matches the type!
621621
self.validate_operand(&self.place_to_op(dest)?)?;
622622
}

compiler/rustc_mir_transform/src/const_prop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
180180
}
181181

182182
#[inline(always)]
183-
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
183+
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
184184
false // for now, we don't enforce validity
185185
}
186186
fn alignment_check_failed(

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
88
use rustc_hir::def::DefKind;
99
use rustc_middle::mir::visit::{MutVisitor, Visitor};
1010
use rustc_middle::mir::*;
11+
use rustc_middle::ty::layout::TyAndLayout;
1112
use rustc_middle::ty::{self, Ty, TyCtxt};
1213
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
1314
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
@@ -548,7 +549,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
548549
unimplemented!()
549550
}
550551

551-
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
552+
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
552553
unimplemented!()
553554
}
554555
fn alignment_check_failed(

src/tools/miri/src/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
812812
}
813813

814814
#[inline(always)]
815-
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
815+
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
816816
ecx.machine.validate
817817
}
818818

tests/ui/consts/const-eval/ub-uninhabit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ union MaybeUninit<T: Copy> {
1414
}
1515

1616
const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
17-
//~^ ERROR it is undefined behavior to use this value
17+
//~^ ERROR evaluation of constant value failed
1818

1919
const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
2020
//~^ ERROR it is undefined behavior to use this value
2121

2222
const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
23-
//~^ ERROR it is undefined behavior to use this value
23+
//~^ ERROR evaluation of constant value failed
2424

2525
fn main() {}

tests/ui/consts/const-eval/ub-uninhabit.stderr

+6-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-uninhabit.rs:16:1
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/ub-uninhabit.rs:16:35
33
|
44
LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
5-
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
6-
|
7-
= 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.
8-
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
96

107
error[E0080]: it is undefined behavior to use this value
118
--> $DIR/ub-uninhabit.rs:19:1
@@ -18,14 +15,11 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
1815
HEX_DUMP
1916
}
2017

21-
error[E0080]: it is undefined behavior to use this value
22-
--> $DIR/ub-uninhabit.rs:22:1
18+
error[E0080]: evaluation of constant value failed
19+
--> $DIR/ub-uninhabit.rs:22:42
2320
|
2421
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
25-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
26-
|
27-
= 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.
28-
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
2923

3024
error: aborting due to 3 previous errors
3125

tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr

+3-6
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,11 @@ note: inside `FOO`
2424
LL | const FOO: [empty::Empty; 3] = [foo(); 3];
2525
| ^^^^^
2626

27-
error[E0080]: it is undefined behavior to use this value
28-
--> $DIR/validate_uninhabited_zsts.rs:21:1
27+
error[E0080]: evaluation of constant value failed
28+
--> $DIR/validate_uninhabited_zsts.rs:21:42
2929
|
3030
LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
31-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void
32-
|
33-
= 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.
34-
= note: the raw bytes of the constant (size: 0, align: 1) {}
31+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void
3532

3633
warning: the type `empty::Empty` does not permit zero-initialization
3734
--> $DIR/validate_uninhabited_zsts.rs:21:42

tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr

+3-6
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,11 @@ note: inside `FOO`
2424
LL | const FOO: [empty::Empty; 3] = [foo(); 3];
2525
| ^^^^^
2626

27-
error[E0080]: it is undefined behavior to use this value
28-
--> $DIR/validate_uninhabited_zsts.rs:21:1
27+
error[E0080]: evaluation of constant value failed
28+
--> $DIR/validate_uninhabited_zsts.rs:21:42
2929
|
3030
LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
31-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void
32-
|
33-
= 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.
34-
= note: the raw bytes of the constant (size: 0, align: 1) {}
31+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void
3532

3633
warning: the type `empty::Empty` does not permit zero-initialization
3734
--> $DIR/validate_uninhabited_zsts.rs:21:42

tests/ui/consts/const-eval/validate_uninhabited_zsts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub mod empty {
1919
const FOO: [empty::Empty; 3] = [foo(); 3];
2020

2121
const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
22-
//~^ ERROR it is undefined behavior to use this value
22+
//~^ ERROR evaluation of constant value failed
2323
//~| WARN the type `empty::Empty` does not permit zero-initialization
2424

2525
fn main() {

tests/ui/consts/issue-64506.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// check-pass
1+
// check-fail
22

33
#[derive(Copy, Clone)]
44
pub struct ChildStdin {
@@ -14,6 +14,7 @@ const FOO: () = {
1414
b: (),
1515
}
1616
let x = unsafe { Foo { b: () }.a };
17+
//~^ ERROR: evaluation of constant value failed
1718
let x = &x.inner;
1819
};
1920

tests/ui/consts/issue-64506.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0080]: evaluation of constant value failed
2+
--> $DIR/issue-64506.rs:16:22
3+
|
4+
LL | let x = unsafe { Foo { b: () }.a };
5+
| ^^^^^^^^^^^^^^^ constructing invalid value at .inner: encountered a value of uninhabited type AnonPipe
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)