mir-interpret now treats unions as non-immediate, even if they have scalar layout, allowing partially initializing them
This commit is contained in:
parent
d32ce37a17
commit
09b291f0b2
@ -15,7 +15,7 @@
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_target::abi::Abi;
|
||||
use rustc_target::abi::{self, Abi};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
|
||||
@ -119,7 +119,7 @@ pub(super) fn op_to_const<'tcx>(
|
||||
// the usual cases of extracting e.g. a `usize`, without there being a real use case for the
|
||||
// `Undef` situation.
|
||||
let try_as_immediate = match op.layout.abi {
|
||||
Abi::Scalar(..) => true,
|
||||
Abi::Scalar(abi::Scalar::Initialized { .. }) => true,
|
||||
Abi::ScalarPair(..) => match op.layout.ty.kind() {
|
||||
ty::Ref(_, inner, _) => match *inner.kind() {
|
||||
ty::Slice(elem) => elem == ecx.tcx.types.u8,
|
||||
|
@ -10,7 +10,7 @@
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
|
||||
use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding};
|
||||
use rustc_target::abi::{self, Abi, HasDataLayout, Size, TagEncoding};
|
||||
use rustc_target::abi::{VariantIdx, Variants};
|
||||
|
||||
use super::{
|
||||
@ -268,14 +268,18 @@ fn try_read_immediate_from_mplace(
|
||||
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
|
||||
// However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
|
||||
// and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
|
||||
// case where some of the bytes are initialized and others are not. So, we only permit
|
||||
// reads from `Scalar`s and `ScalarPair`s that cannot be uninitialized.
|
||||
// case where some of the bytes are initialized and others are not. So, we need an extra
|
||||
// check that walks over the type of `mplace` to make sure it is truly correct to treat this
|
||||
// like a `Scalar` (or `ScalarPair`).
|
||||
match mplace.layout.abi {
|
||||
Abi::Scalar(..) => {
|
||||
Abi::Scalar(abi::Scalar::Initialized { .. }) => {
|
||||
let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
|
||||
Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
|
||||
}
|
||||
Abi::ScalarPair(a, b) => {
|
||||
Abi::ScalarPair(
|
||||
abi::Scalar::Initialized { value: a, .. },
|
||||
abi::Scalar::Initialized { value: b, .. },
|
||||
) => {
|
||||
// We checked `ptr_align` above, so all fields will have the alignment they need.
|
||||
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
|
||||
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
|
||||
|
@ -3,56 +3,70 @@
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
|
||||
let _1: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
|
||||
let mut _3: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:46
|
||||
let mut _5: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:56
|
||||
let _1: char; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
|
||||
let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:34: 21:63
|
||||
let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:59
|
||||
let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:34: 28:55
|
||||
let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:73
|
||||
let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:44: 35:65
|
||||
scope 1 {
|
||||
debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:21:9: 21:22
|
||||
let _2: [main::InvalidTag; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
|
||||
scope 2 {
|
||||
debug _invalid_tag => _2; // in scope 2 at $DIR/invalid_constant.rs:28:9: 28:21
|
||||
let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
|
||||
scope 3 {
|
||||
debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
|
||||
let _6: main::Str<"<22><><EFBFBD>">; // in scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
|
||||
scope 4 {
|
||||
debug _non_utf8_str => _6; // in scope 4 at $DIR/invalid_constant.rs:39:9: 39:22
|
||||
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
|
||||
scope 3 {
|
||||
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:28:9: 28:21
|
||||
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
|
||||
scope 5 {
|
||||
debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:35:9: 35:31
|
||||
let _9: main::Str<"<22><><EFBFBD>">; // in scope 5 at $DIR/invalid_constant.rs:39:9: 39:22
|
||||
scope 7 {
|
||||
debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:39:9: 39:22
|
||||
}
|
||||
}
|
||||
scope 6 {
|
||||
}
|
||||
}
|
||||
scope 4 {
|
||||
}
|
||||
}
|
||||
scope 2 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
|
||||
- _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
|
||||
+ _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
|
||||
// mir::Constant
|
||||
// + span: $DIR/invalid_constant.rs:21:25: 21:64
|
||||
- // + literal: Const { ty: InvalidChar, val: Unevaluated(main::{constant#0}, [main::InvalidChar], None) }
|
||||
+ // + literal: Const { ty: InvalidChar, val: Value(Scalar(0x00110001)) }
|
||||
StorageLive(_2); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
|
||||
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
|
||||
(_3.0: u32) = const 4_u32; // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
|
||||
- _2 = [move _3]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
|
||||
+ _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
|
||||
StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
|
||||
(_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
|
||||
- _1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
|
||||
+ _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
|
||||
StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:21:69: 21:70
|
||||
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
|
||||
StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:59
|
||||
StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
|
||||
(_5.0: u32) = const 4_u32; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
|
||||
- _4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
|
||||
- _3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
|
||||
+ _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
|
||||
+ // mir::Constant
|
||||
+ // + span: $DIR/invalid_constant.rs:28:24: 28:47
|
||||
+ // + literal: Const { ty: InvalidTag, val: Value(Scalar(0x00000004)) }
|
||||
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:28:46: 28:47
|
||||
StorageLive(_4); // scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
|
||||
StorageLive(_5); // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
|
||||
(_5.0: u32) = const 0_u32; // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
|
||||
- _4 = [move _5]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
|
||||
+ _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
|
||||
+ // + span: $DIR/invalid_constant.rs:28:34: 28:57
|
||||
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
|
||||
+ _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
|
||||
+ // mir::Constant
|
||||
+ // + span: $DIR/invalid_constant.rs:35:34: 35:57
|
||||
+ // + literal: Const { ty: NoVariants, val: Value(Scalar(0x00000000)) }
|
||||
StorageDead(_5); // scope 2 at $DIR/invalid_constant.rs:35:56: 35:57
|
||||
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
|
||||
+ // + span: $DIR/invalid_constant.rs:28:24: 28:60
|
||||
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
|
||||
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:28:59: 28:60
|
||||
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:28:60: 28:61
|
||||
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
|
||||
StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:35:35: 35:73
|
||||
StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
|
||||
(_8.0: u32) = const 0_u32; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
|
||||
nop; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:71
|
||||
nop; // scope 3 at $DIR/invalid_constant.rs:35:34: 35:74
|
||||
StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:35:73: 35:74
|
||||
StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:35:74: 35:75
|
||||
StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:39:9: 39:22
|
||||
nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 42:2
|
||||
StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:42:1: 42:2
|
||||
StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:42:1: 42:2
|
||||
StorageDead(_4); // scope 2 at $DIR/invalid_constant.rs:42:1: 42:2
|
||||
StorageDead(_2); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
|
||||
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
|
||||
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:42:1: 42:2
|
||||
return; // scope 0 at $DIR/invalid_constant.rs:42:2: 42:2
|
||||
}
|
||||
|
@ -18,21 +18,21 @@ union InvalidChar {
|
||||
int: u32,
|
||||
chr: char,
|
||||
}
|
||||
let _invalid_char = const { InvalidChar { int: 0x110001 } };
|
||||
let _invalid_char = unsafe { InvalidChar { int: 0x110001 }.chr };
|
||||
|
||||
// An enum with an invalid tag. Regression test for #93688.
|
||||
union InvalidTag {
|
||||
int: u32,
|
||||
e: E,
|
||||
}
|
||||
let _invalid_tag = [InvalidTag { int: 4 }];
|
||||
let _invalid_tag = [unsafe { InvalidTag { int: 4 }.e }];
|
||||
|
||||
// An enum without variants. Regression test for #94073.
|
||||
union NoVariants {
|
||||
int: u32,
|
||||
empty: Empty,
|
||||
}
|
||||
let _enum_without_variants = [NoVariants { int: 0 }];
|
||||
let _enum_without_variants = [unsafe { NoVariants { int: 0 }.empty }];
|
||||
|
||||
// A non-UTF-8 string slice. Regression test for #75763 and #78520.
|
||||
struct Str<const S: &'static str>;
|
||||
|
34
src/test/ui/consts/issue-69488.rs
Normal file
34
src/test/ui/consts/issue-69488.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(const_ptr_write)]
|
||||
#![feature(const_mut_refs)]
|
||||
|
||||
// Or, equivalently: `MaybeUninit`.
|
||||
pub union BagOfBits<T: Copy> {
|
||||
uninit: (),
|
||||
_storage: T,
|
||||
}
|
||||
|
||||
pub const fn make_1u8_bag<T: Copy>() -> BagOfBits<T> {
|
||||
assert!(core::mem::size_of::<T>() >= 1);
|
||||
let mut bag = BagOfBits { uninit: () };
|
||||
unsafe { (&mut bag as *mut _ as *mut u8).write(1); };
|
||||
bag
|
||||
}
|
||||
|
||||
pub fn check_bag<T: Copy>(bag: &BagOfBits<T>) {
|
||||
let val = unsafe { (bag as *const _ as *const u8).read() };
|
||||
assert_eq!(val, 1);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check_bag(&make_1u8_bag::<[usize; 1]>()); // Fine
|
||||
check_bag(&make_1u8_bag::<usize>()); // Fine
|
||||
|
||||
const CONST_ARRAY_BAG: BagOfBits<[usize; 1]> = make_1u8_bag();
|
||||
check_bag(&CONST_ARRAY_BAG); // Fine.
|
||||
const CONST_USIZE_BAG: BagOfBits<usize> = make_1u8_bag();
|
||||
|
||||
// Used to panic since CTFE would make the entire `BagOfBits<usize>` uninit
|
||||
check_bag(&CONST_USIZE_BAG);
|
||||
}
|
16
src/test/ui/consts/issue-94371.rs
Normal file
16
src/test/ui/consts/issue-94371.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(const_swap)]
|
||||
#![feature(const_mut_refs)]
|
||||
|
||||
#[repr(C)]
|
||||
struct Demo(u64, bool, u64, u32, u64, u64, u64);
|
||||
|
||||
const C: (Demo, Demo) = {
|
||||
let mut x = Demo(1, true, 3, 4, 5, 6, 7);
|
||||
let mut y = Demo(10, false, 12, 13, 14, 15, 16);
|
||||
std::mem::swap(&mut x, &mut y);
|
||||
(x, y)
|
||||
};
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user