1
Fork 0

don't allow ZST in ScalarInt

There are several indications that we should not ZST as a ScalarInt:
- We had two ways to have ZST valtrees, either an empty `Branch` or a `Leaf` with a ZST in it.
  `ValTree::zst()` used the former, but the latter could possibly arise as well.
- Likewise, the interpreter had `Immediate::Uninit` and `Immediate::Scalar(Scalar::ZST)`.
- LLVM codegen already had to special-case ZST ScalarInt.

So instead add new ZST variants to those types that did not have other variants
which could be used for this purpose.
This commit is contained in:
Ralf Jung 2022-07-03 11:17:23 -04:00
parent c4693bc946
commit a422b42159
21 changed files with 78 additions and 61 deletions

View file

@ -2,7 +2,7 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
ScalarMaybeUninit, StackPopCleanup,
};
@ -157,7 +157,7 @@ pub(super) fn op_to_const<'tcx>(
"this MPlaceTy must come from a validated constant, thus we can assume the \
alignment is correct",
);
ConstValue::Scalar(Scalar::ZST)
ConstValue::ZST
}
}
};

View file

@ -272,7 +272,7 @@ pub fn valtree_to_const_value<'tcx>(
match ty.kind() {
ty::FnDef(..) => {
assert!(valtree.unwrap_branch().is_empty());
ConstValue::Scalar(Scalar::ZST)
ConstValue::ZST
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
ty::ValTree::Leaf(scalar_int) => ConstValue::Scalar(Scalar::Int(scalar_int)),
@ -344,11 +344,7 @@ fn valtree_into_mplace<'tcx>(
match ty.kind() {
ty::FnDef(_, _) => {
ecx.write_immediate(
Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
&place.into(),
)
.unwrap();
ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap();
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf();

View file

@ -297,8 +297,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let Some(alloc) = self.get_place_alloc(mplace)? else {
return Ok(Some(ImmTy {
// zero-sized type
imm: Scalar::ZST.into(),
// zero-sized type can be left uninit
imm: Immediate::Uninit,
layout: mplace.layout,
}));
};
@ -441,8 +441,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// This makes several assumptions about what layouts we will encounter; we match what
// codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
let field_val: Immediate<_> = match (*base, base.layout.abi) {
// the field contains no information
_ if field_layout.is_zst() => Scalar::ZST.into(),
// the field contains no information, can be left uninit
_ if field_layout.is_zst() => Immediate::Uninit,
// the field covers the entire type
_ if field_layout.size == base.layout.size => {
assert!(match (base.layout.abi, field_layout.abi) {
@ -553,8 +553,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let layout = self.layout_of_local(frame, local, layout)?;
let op = if layout.is_zst() {
// Do not read from ZST, they might not be initialized
Operand::Immediate(Scalar::ZST.into())
// Bypass `access_local` (helps in ConstProp)
Operand::Immediate(Immediate::Uninit)
} else {
*M::access_local(frame, local)?
};
@ -709,6 +709,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Operand::Indirect(MemPlace::from_ptr(ptr.into()))
}
ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
ConstValue::ZST => Operand::Immediate(Immediate::Uninit),
ConstValue::Slice { data, start, end } => {
// We rely on mutability being set correctly in `data` to prevent writes
// where none should happen.