Skip to content

Commit 27c4f88

Browse files
committed
Modify const eval to implement the new semantics for SetDiscriminant.
1 parent 1cdeb7f commit 27c4f88

File tree

4 files changed

+56
-1
lines changed

4 files changed

+56
-1
lines changed

compiler/rustc_const_eval/src/interpret/memory.rs

+5
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,11 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
908908
) -> InterpResult<'tcx> {
909909
self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
910910
}
911+
912+
/// Mark the entire referenced range as uninitalized
913+
pub fn write_uninit(&mut self) {
914+
self.alloc.mark_init(self.range, false);
915+
}
911916
}
912917

913918
impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {

compiler/rustc_const_eval/src/interpret/place.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,16 @@ where
793793
}
794794
}
795795

796+
fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
797+
let mplace = self.force_allocation(dest)?;
798+
let Some(mut alloc) = self.get_alloc_mut(&mplace)? else {
799+
// Zero-sized access
800+
return Ok(());
801+
};
802+
alloc.write_uninit();
803+
Ok(())
804+
}
805+
796806
/// Copies the data from an operand to a place. This does not support transmuting!
797807
/// Use `copy_op_transmute` if the layouts could disagree.
798808
#[inline(always)]
@@ -1011,7 +1021,10 @@ where
10111021
) -> InterpResult<'tcx> {
10121022
// This must be an enum or generator.
10131023
match dest.layout.ty.kind() {
1014-
ty::Adt(adt, _) => assert!(adt.is_enum()),
1024+
ty::Adt(adt, _) => {
1025+
assert!(adt.is_enum());
1026+
self.write_uninit(dest)?;
1027+
}
10151028
ty::Generator(..) => {}
10161029
_ => span_bug!(
10171030
self.cur_span(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(const_mut_refs)]
2+
3+
enum E {
4+
A(u8),
5+
B,
6+
}
7+
8+
const _: u8 = {
9+
//~^ ERROR is undefined behavior
10+
let mut e = E::A(1);
11+
let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() };
12+
// Make sure overwriting `e` uninitializes other bytes
13+
e = E::B;
14+
unsafe { *p }
15+
};
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0080]: it is undefined behavior to use this value
2+
--> $DIR/ub-enum-overwrite.rs:8:1
3+
|
4+
LL | / const _: u8 = {
5+
LL | |
6+
LL | | let mut e = E::A(1);
7+
LL | | let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() };
8+
... |
9+
LL | | unsafe { *p }
10+
LL | | };
11+
| |__^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
12+
|
13+
= 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.
14+
= note: the raw bytes of the constant (size: 1, align: 1) {
15+
__ │ ░
16+
}
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)