Change:
It looks like this was broken in the release of 1.32.0 (and is still broken, even on nightly) (checked on ). The following example program: Fails to compile: Interestingly, making the fixes it. My Rust version: I know , but I don't think this qualifies as a field access. And yes, I'm aware of . cc
Interesting. Looks like a validation issue? Cc

Discussion:
fn mplace_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, mplace: MPlaceTy<'tcx>, <del> ) -> EvalResult<'tcx, ty::Const<'tcx>> { </del> <ins> ) -> ty::Const<'tcx> { </ins> let MemPlace { ptr, align, meta } = *mplace; // extract alloc-offset pair assert!(meta.is_none()); <del> let ptr = ptr.to_ptr()?; let alloc = ecx.memory.get(ptr.alloc_id)?; </del> <ins> let ptr = ptr.to_ptr().unwrap(); let alloc = ecx.memory.get(ptr.alloc_id).unwrap(); </ins> assert!(alloc.align >= align); assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= mplace.layout.size.bytes()); let mut alloc = alloc.clone();

// interned this?  I thought that is the entire point of that `FinishStatic` stuff? let alloc = ecx.tcx.intern_const_alloc(alloc); let val = ConstValue::ByRef(ptr, alloc); <del> Ok(ty::Const { val, ty: mplace.layout.ty }) </del> <ins> ty::Const { val, ty: mplace.layout.ty } </ins> } fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, op: OpTy<'tcx>, <del> ) -> EvalResult<'tcx, ty::Const<'tcx>> { // We do not normalize just any data.  Only scalar layout and slices. </del> <ins> ) -> ty::Const<'tcx> { // We do not normalize just any data.  Only non-union scalars and slices. </ins> let normalize = match op.layout.abi { <del> layout::Abi::Scalar(..) => true, </del> <ins> layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()), </ins> layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(), _ => false, };

let val = match normalized_op { Ok(mplace) => return mplace_to_const(ecx, mplace), Err(Immediate::Scalar(x)) => <del> ConstValue::Scalar(x.not_undef()?), </del> <ins> ConstValue::Scalar(x.not_undef().unwrap()), </ins> Err(Immediate::ScalarPair(a, b)) => <del> ConstValue::Slice(a.not_undef()?, b.to_usize(ecx)?), </del> <ins> ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()), </ins> }; <del> Ok(ty::Const { val, ty: op.layout.ty }) </del> <ins> ty::Const { val, ty: op.layout.ty } </ins> } fn eval_body_and_ecx<'a, 'mir, 'tcx>(

let field = ecx.operand_field(down, field.index() as u64).unwrap(); // and finally move back to the const world, always normalizing because // this is not called for statics. <del> op_to_const(&ecx, field).unwrap() </del> <ins> op_to_const(&ecx, field) </ins> } // this function uses `unwrap` copiously, because an already validated constant must have valid

// Now that we validated, turn this into a proper constant. let def_id = cid.instance.def.def_id(); if tcx.is_static(def_id).is_some() || cid.promoted.is_some() { <del> mplace_to_const(&ecx, mplace) </del> <ins> Ok(mplace_to_const(&ecx, mplace)) </ins> } else { <del> op_to_const(&ecx, mplace.into()) </del> <ins> Ok(op_to_const(&ecx, mplace.into())) </ins> } })();

<ins> // compile-pass union Uninit { _never_use: *const u8, uninit: (), } const UNINIT: Uninit = Uninit { uninit: () }; fn main() {} </ins>