Skip to content

Commit 09b291f

Browse files
committed
mir-interpret now treats unions as non-immediate, even if they have scalar layout, allowing partially initializing them
1 parent d32ce37 commit 09b291f

File tree

6 files changed

+115
-47
lines changed

6 files changed

+115
-47
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf;
1515
use rustc_middle::ty::print::with_no_trimmed_paths;
1616
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
1717
use rustc_span::source_map::Span;
18-
use rustc_target::abi::Abi;
18+
use rustc_target::abi::{self, Abi};
1919
use std::borrow::Cow;
2020
use std::convert::TryInto;
2121

@@ -119,7 +119,7 @@ pub(super) fn op_to_const<'tcx>(
119119
// the usual cases of extracting e.g. a `usize`, without there being a real use case for the
120120
// `Undef` situation.
121121
let try_as_immediate = match op.layout.abi {
122-
Abi::Scalar(..) => true,
122+
Abi::Scalar(abi::Scalar::Initialized { .. }) => true,
123123
Abi::ScalarPair(..) => match op.layout.ty.kind() {
124124
ty::Ref(_, inner, _) => match *inner.kind() {
125125
ty::Slice(elem) => elem == ecx.tcx.types.u8,

compiler/rustc_const_eval/src/interpret/operand.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
1010
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
1111
use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
1212
use rustc_middle::{mir, ty};
13-
use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding};
13+
use rustc_target::abi::{self, Abi, HasDataLayout, Size, TagEncoding};
1414
use rustc_target::abi::{VariantIdx, Variants};
1515

1616
use super::{
@@ -268,14 +268,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
268268
// It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
269269
// However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
270270
// and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
271-
// case where some of the bytes are initialized and others are not. So, we only permit
272-
// reads from `Scalar`s and `ScalarPair`s that cannot be uninitialized.
271+
// case where some of the bytes are initialized and others are not. So, we need an extra
272+
// check that walks over the type of `mplace` to make sure it is truly correct to treat this
273+
// like a `Scalar` (or `ScalarPair`).
273274
match mplace.layout.abi {
274-
Abi::Scalar(..) => {
275+
Abi::Scalar(abi::Scalar::Initialized { .. }) => {
275276
let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
276277
Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
277278
}
278-
Abi::ScalarPair(a, b) => {
279+
Abi::ScalarPair(
280+
abi::Scalar::Initialized { value: a, .. },
281+
abi::Scalar::Initialized { value: b, .. },
282+
) => {
279283
// We checked `ptr_align` above, so all fields will have the alignment they need.
280284
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
281285
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.

src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff

+51-37
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,70 @@
33

44
fn main() -> () {
55
let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
6-
let _1: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
7-
let mut _3: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:46
8-
let mut _5: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:56
6+
let _1: char; // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
7+
let mut _2: main::InvalidChar; // in scope 0 at $DIR/invalid_constant.rs:21:34: 21:63
8+
let mut _4: E; // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:59
9+
let mut _5: main::InvalidTag; // in scope 0 at $DIR/invalid_constant.rs:28:34: 28:55
10+
let mut _7: Empty; // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:73
11+
let mut _8: main::NoVariants; // in scope 0 at $DIR/invalid_constant.rs:35:44: 35:65
912
scope 1 {
1013
debug _invalid_char => _1; // in scope 1 at $DIR/invalid_constant.rs:21:9: 21:22
11-
let _2: [main::InvalidTag; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
12-
scope 2 {
13-
debug _invalid_tag => _2; // in scope 2 at $DIR/invalid_constant.rs:28:9: 28:21
14-
let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
15-
scope 3 {
16-
debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
17-
let _6: main::Str<"���">; // in scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
18-
scope 4 {
19-
debug _non_utf8_str => _6; // in scope 4 at $DIR/invalid_constant.rs:39:9: 39:22
14+
let _3: [E; 1]; // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
15+
scope 3 {
16+
debug _invalid_tag => _3; // in scope 3 at $DIR/invalid_constant.rs:28:9: 28:21
17+
let _6: [Empty; 1]; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
18+
scope 5 {
19+
debug _enum_without_variants => _6; // in scope 5 at $DIR/invalid_constant.rs:35:9: 35:31
20+
let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:39:9: 39:22
21+
scope 7 {
22+
debug _non_utf8_str => _9; // in scope 7 at $DIR/invalid_constant.rs:39:9: 39:22
2023
}
2124
}
25+
scope 6 {
26+
}
27+
}
28+
scope 4 {
2229
}
2330
}
31+
scope 2 {
32+
}
2433

2534
bb0: {
2635
StorageLive(_1); // scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
27-
- _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
28-
+ _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
29-
// mir::Constant
30-
// + span: $DIR/invalid_constant.rs:21:25: 21:64
31-
- // + literal: Const { ty: InvalidChar, val: Unevaluated(main::{constant#0}, [main::InvalidChar], None) }
32-
+ // + literal: Const { ty: InvalidChar, val: Value(Scalar(0x00110001)) }
33-
StorageLive(_2); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
34-
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
35-
(_3.0: u32) = const 4_u32; // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
36-
- _2 = [move _3]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
37-
+ _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
36+
StorageLive(_2); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
37+
(_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
38+
- _1 = (_2.1: char); // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
39+
+ _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
40+
StorageDead(_2); // scope 0 at $DIR/invalid_constant.rs:21:69: 21:70
41+
StorageLive(_3); // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
42+
StorageLive(_4); // scope 1 at $DIR/invalid_constant.rs:28:25: 28:59
43+
StorageLive(_5); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
44+
(_5.0: u32) = const 4_u32; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
45+
- _4 = (_5.1: E); // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
46+
- _3 = [move _4]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
47+
+ _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
3848
+ // mir::Constant
39-
+ // + span: $DIR/invalid_constant.rs:28:24: 28:47
40-
+ // + literal: Const { ty: InvalidTag, val: Value(Scalar(0x00000004)) }
41-
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:28:46: 28:47
42-
StorageLive(_4); // scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
43-
StorageLive(_5); // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
44-
(_5.0: u32) = const 0_u32; // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
45-
- _4 = [move _5]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
46-
+ _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
49+
+ // + span: $DIR/invalid_constant.rs:28:34: 28:57
50+
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
51+
+ _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
4752
+ // mir::Constant
48-
+ // + span: $DIR/invalid_constant.rs:35:34: 35:57
49-
+ // + literal: Const { ty: NoVariants, val: Value(Scalar(0x00000000)) }
50-
StorageDead(_5); // scope 2 at $DIR/invalid_constant.rs:35:56: 35:57
51-
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
53+
+ // + span: $DIR/invalid_constant.rs:28:24: 28:60
54+
+ // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
55+
StorageDead(_4); // scope 1 at $DIR/invalid_constant.rs:28:59: 28:60
56+
StorageDead(_5); // scope 1 at $DIR/invalid_constant.rs:28:60: 28:61
57+
StorageLive(_6); // scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
58+
StorageLive(_7); // scope 3 at $DIR/invalid_constant.rs:35:35: 35:73
59+
StorageLive(_8); // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
60+
(_8.0: u32) = const 0_u32; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
61+
nop; // scope 6 at $DIR/invalid_constant.rs:35:44: 35:71
62+
nop; // scope 3 at $DIR/invalid_constant.rs:35:34: 35:74
63+
StorageDead(_7); // scope 3 at $DIR/invalid_constant.rs:35:73: 35:74
64+
StorageDead(_8); // scope 3 at $DIR/invalid_constant.rs:35:74: 35:75
65+
StorageLive(_9); // scope 5 at $DIR/invalid_constant.rs:39:9: 39:22
5266
nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 42:2
67+
StorageDead(_9); // scope 5 at $DIR/invalid_constant.rs:42:1: 42:2
5368
StorageDead(_6); // scope 3 at $DIR/invalid_constant.rs:42:1: 42:2
54-
StorageDead(_4); // scope 2 at $DIR/invalid_constant.rs:42:1: 42:2
55-
StorageDead(_2); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
69+
StorageDead(_3); // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
5670
StorageDead(_1); // scope 0 at $DIR/invalid_constant.rs:42:1: 42:2
5771
return; // scope 0 at $DIR/invalid_constant.rs:42:2: 42:2
5872
}

src/test/mir-opt/const_prop/invalid_constant.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ fn main() {
1818
int: u32,
1919
chr: char,
2020
}
21-
let _invalid_char = const { InvalidChar { int: 0x110001 } };
21+
let _invalid_char = unsafe { InvalidChar { int: 0x110001 }.chr };
2222

2323
// An enum with an invalid tag. Regression test for #93688.
2424
union InvalidTag {
2525
int: u32,
2626
e: E,
2727
}
28-
let _invalid_tag = [InvalidTag { int: 4 }];
28+
let _invalid_tag = [unsafe { InvalidTag { int: 4 }.e }];
2929

3030
// An enum without variants. Regression test for #94073.
3131
union NoVariants {
3232
int: u32,
3333
empty: Empty,
3434
}
35-
let _enum_without_variants = [NoVariants { int: 0 }];
35+
let _enum_without_variants = [unsafe { NoVariants { int: 0 }.empty }];
3636

3737
// A non-UTF-8 string slice. Regression test for #75763 and #78520.
3838
struct Str<const S: &'static str>;

src/test/ui/consts/issue-69488.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// run-pass
2+
3+
#![feature(const_ptr_write)]
4+
#![feature(const_mut_refs)]
5+
6+
// Or, equivalently: `MaybeUninit`.
7+
pub union BagOfBits<T: Copy> {
8+
uninit: (),
9+
_storage: T,
10+
}
11+
12+
pub const fn make_1u8_bag<T: Copy>() -> BagOfBits<T> {
13+
assert!(core::mem::size_of::<T>() >= 1);
14+
let mut bag = BagOfBits { uninit: () };
15+
unsafe { (&mut bag as *mut _ as *mut u8).write(1); };
16+
bag
17+
}
18+
19+
pub fn check_bag<T: Copy>(bag: &BagOfBits<T>) {
20+
let val = unsafe { (bag as *const _ as *const u8).read() };
21+
assert_eq!(val, 1);
22+
}
23+
24+
fn main() {
25+
check_bag(&make_1u8_bag::<[usize; 1]>()); // Fine
26+
check_bag(&make_1u8_bag::<usize>()); // Fine
27+
28+
const CONST_ARRAY_BAG: BagOfBits<[usize; 1]> = make_1u8_bag();
29+
check_bag(&CONST_ARRAY_BAG); // Fine.
30+
const CONST_USIZE_BAG: BagOfBits<usize> = make_1u8_bag();
31+
32+
// Used to panic since CTFE would make the entire `BagOfBits<usize>` uninit
33+
check_bag(&CONST_USIZE_BAG);
34+
}

src/test/ui/consts/issue-94371.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// check-pass
2+
3+
#![feature(const_swap)]
4+
#![feature(const_mut_refs)]
5+
6+
#[repr(C)]
7+
struct Demo(u64, bool, u64, u32, u64, u64, u64);
8+
9+
const C: (Demo, Demo) = {
10+
let mut x = Demo(1, true, 3, 4, 5, 6, 7);
11+
let mut y = Demo(10, false, 12, 13, 14, 15, 16);
12+
std::mem::swap(&mut x, &mut y);
13+
(x, y)
14+
};
15+
16+
fn main() {}

0 commit comments

Comments
 (0)