Skip to content

Commit

Permalink
Modify const eval to implement the new semantics for SetDiscriminant.
Browse files Browse the repository at this point in the history
  • Loading branch information
JakobDegen committed Mar 13, 2022
1 parent 1cdeb7f commit 27c4f88
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
5 changes: 5 additions & 0 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,11 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
) -> InterpResult<'tcx> {
self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
}

/// Mark the entire referenced range as uninitalized
pub fn write_uninit(&mut self) {
self.alloc.mark_init(self.range, false);
}
}

impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,16 @@ where
}
}

fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
let mplace = self.force_allocation(dest)?;
let Some(mut alloc) = self.get_alloc_mut(&mplace)? else {
// Zero-sized access
return Ok(());
};
alloc.write_uninit();
Ok(())
}

/// Copies the data from an operand to a place. This does not support transmuting!
/// Use `copy_op_transmute` if the layouts could disagree.
#[inline(always)]
Expand Down Expand Up @@ -1011,7 +1021,10 @@ where
) -> InterpResult<'tcx> {
// This must be an enum or generator.
match dest.layout.ty.kind() {
ty::Adt(adt, _) => assert!(adt.is_enum()),
ty::Adt(adt, _) => {
assert!(adt.is_enum());
self.write_uninit(dest)?;
}
ty::Generator(..) => {}
_ => span_bug!(
self.cur_span(),
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/consts/const-eval/ub-enum-overwrite.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(const_mut_refs)]

enum E {
A(u8),
B,
}

const _: u8 = {
//~^ ERROR is undefined behavior
let mut e = E::A(1);
let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() };
// Make sure overwriting `e` uninitializes other bytes
e = E::B;
unsafe { *p }
};

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/consts/const-eval/ub-enum-overwrite.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum-overwrite.rs:8:1
|
LL | / const _: u8 = {
LL | |
LL | | let mut e = E::A(1);
LL | | let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() };
... |
LL | | unsafe { *p }
LL | | };
| |__^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= 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: 1, align: 1) {
__ │ ░
}

error: aborting due to previous error

For more information about this error, try `rustc --explain E0080`.

0 comments on commit 27c4f88

Please sign in to comment.