mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Rollup merge of #109435 - oli-obk:🇨🇭🥚_copy_op, r=RalfJung
Detect uninhabited types early in const eval r? `@RalfJung` implements https://github.com/rust-lang/rust/pull/108442#discussion_r1143003840 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.
This commit is contained in:
commit
eda88a30c7
@ -2,7 +2,7 @@ use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{LangItem, CRATE_HIR_ID};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::PointerArithmetic;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
|
||||
use std::borrow::Borrow;
|
||||
@ -335,8 +335,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
|
||||
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
|
||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
|
||||
}
|
||||
|
||||
fn alignment_check_failed(
|
||||
|
@ -8,6 +8,7 @@ use std::hash::Hash;
|
||||
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::abi::{Align, Size};
|
||||
@ -145,8 +146,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
check: CheckAlignment,
|
||||
) -> InterpResult<'tcx, ()>;
|
||||
|
||||
/// Whether to enforce the validity invariant
|
||||
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
|
||||
/// Whether to enforce the validity invariant for a specific layout.
|
||||
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;
|
||||
|
||||
/// Whether function calls should be [ABI](CallAbi)-checked.
|
||||
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
|
@ -461,7 +461,7 @@ where
|
||||
) -> InterpResult<'tcx> {
|
||||
self.write_immediate_no_validate(src, dest)?;
|
||||
|
||||
if M::enforce_validity(self) {
|
||||
if M::enforce_validity(self, dest.layout) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(&self.place_to_op(dest)?)?;
|
||||
}
|
||||
@ -616,7 +616,7 @@ where
|
||||
) -> InterpResult<'tcx> {
|
||||
self.copy_op_no_validate(src, dest, allow_transmute)?;
|
||||
|
||||
if M::enforce_validity(self) {
|
||||
if M::enforce_validity(self, dest.layout) {
|
||||
// Data got changed, better make sure it matches the type!
|
||||
self.validate_operand(&self.place_to_op(dest)?)?;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
|
||||
false // for now, we don't enforce validity
|
||||
}
|
||||
fn alignment_check_failed(
|
||||
|
@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::mir::visit::{MutVisitor, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
|
||||
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
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
|
||||
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
fn alignment_check_failed(
|
||||
|
@ -812,7 +812,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
|
||||
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
|
||||
ecx.machine.validate
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,12 @@ union MaybeUninit<T: Copy> {
|
||||
}
|
||||
|
||||
const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
|
||||
const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
|
||||
const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,11 +1,8 @@
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-uninhabit.rs:16:1
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/ub-uninhabit.rs:16:35
|
||||
|
|
||||
LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
|
||||
|
|
||||
= 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.
|
||||
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-uninhabit.rs:19:1
|
||||
@ -18,14 +15,11 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
|
||||
HEX_DUMP
|
||||
}
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-uninhabit.rs:22:1
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/ub-uninhabit.rs:22:42
|
||||
|
|
||||
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
|
||||
|
|
||||
= 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.
|
||||
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -24,14 +24,11 @@ note: inside `FOO`
|
||||
LL | const FOO: [empty::Empty; 3] = [foo(); 3];
|
||||
| ^^^^^
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/validate_uninhabited_zsts.rs:21:1
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/validate_uninhabited_zsts.rs:21:42
|
||||
|
|
||||
LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void
|
||||
|
|
||||
= 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.
|
||||
= note: the raw bytes of the constant (size: 0, align: 1) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void
|
||||
|
||||
warning: the type `empty::Empty` does not permit zero-initialization
|
||||
--> $DIR/validate_uninhabited_zsts.rs:21:42
|
||||
|
@ -24,14 +24,11 @@ note: inside `FOO`
|
||||
LL | const FOO: [empty::Empty; 3] = [foo(); 3];
|
||||
| ^^^^^
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/validate_uninhabited_zsts.rs:21:1
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/validate_uninhabited_zsts.rs:21:42
|
||||
|
|
||||
LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void
|
||||
|
|
||||
= 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.
|
||||
= note: the raw bytes of the constant (size: 0, align: 1) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void
|
||||
|
||||
warning: the type `empty::Empty` does not permit zero-initialization
|
||||
--> $DIR/validate_uninhabited_zsts.rs:21:42
|
||||
|
@ -19,7 +19,7 @@ pub mod empty {
|
||||
const FOO: [empty::Empty; 3] = [foo(); 3];
|
||||
|
||||
const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
//~| WARN the type `empty::Empty` does not permit zero-initialization
|
||||
|
||||
fn main() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// check-pass
|
||||
// check-fail
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ChildStdin {
|
||||
@ -14,6 +14,7 @@ const FOO: () = {
|
||||
b: (),
|
||||
}
|
||||
let x = unsafe { Foo { b: () }.a };
|
||||
//~^ ERROR: evaluation of constant value failed
|
||||
let x = &x.inner;
|
||||
};
|
||||
|
||||
|
9
tests/ui/consts/issue-64506.stderr
Normal file
9
tests/ui/consts/issue-64506.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-64506.rs:16:22
|
||||
|
|
||||
LL | let x = unsafe { Foo { b: () }.a };
|
||||
| ^^^^^^^^^^^^^^^ constructing invalid value at .inner: encountered a value of uninhabited type AnonPipe
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
Loading…
Reference in New Issue
Block a user