1
Fork 0

Add new Deinit statement kind

This commit is contained in:
Jakob Degen 2022-04-05 17:14:59 -04:00
parent d00e77078c
commit 9b6b1a625b
27 changed files with 141 additions and 66 deletions

View file

@ -890,6 +890,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> {

View file

@ -791,6 +791,42 @@ where
}
}
pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
let mplace = match dest.place {
Place::Ptr(mplace) => MPlaceTy { mplace, layout: dest.layout },
Place::Local { frame, local } => {
match M::access_local_mut(self, frame, local)? {
Ok(local) => match dest.layout.abi {
Abi::Scalar(_) => {
*local = LocalValue::Live(Operand::Immediate(Immediate::Scalar(
ScalarMaybeUninit::Uninit,
)));
return Ok(());
}
Abi::ScalarPair(..) => {
*local = LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(
ScalarMaybeUninit::Uninit,
ScalarMaybeUninit::Uninit,
)));
return Ok(());
}
_ => self.force_allocation(dest)?,
},
Err(mplace) => {
// The local is in memory, go on below.
MPlaceTy { mplace, layout: dest.layout }
}
}
}
};
let Some(mut alloc) = self.get_place_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)]

View file

@ -90,6 +90,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_discriminant(*variant_index, &dest)?;
}
Deinit(place) => {
let dest = self.eval_place(**place)?;
self.write_uninit(&dest)?;
}
// Mark locals as alive
StorageLive(local) => {
self.storage_live(*local)?;

View file

@ -692,6 +692,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
match statement.kind {
StatementKind::Assign(..)
| StatementKind::SetDiscriminant { .. }
| StatementKind::Deinit(..)
| StatementKind::FakeRead(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)

View file

@ -346,9 +346,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty))
}
}
StatementKind::SetDiscriminant { .. } => {
if self.mir_phase < MirPhase::DropsLowered {
self.fail(location, "`SetDiscriminant` is not allowed until drop elaboration");
StatementKind::SetDiscriminant { place, .. } => {
if self.mir_phase < MirPhase::Deaggregated {
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
}
let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
if !matches!(pty, ty::Adt(..) | ty::Generator(..) | ty::Opaque(..)) {
self.fail(
location,
format!(
"`SetDiscriminant` is only allowed on ADTs and generators, not {:?}",
pty
),
);
}
}
StatementKind::Deinit(..) => {
if self.mir_phase < MirPhase::Deaggregated {
self.fail(location, "`Deinit`is not allowed until deaggregation");
}
}
StatementKind::Retag(_, _) => {

View file

@ -14,22 +14,26 @@ use std::iter::TrustedLen;
/// (lhs as Variant).field1 = arg1;
/// discriminant(lhs) = variant_index; // If lhs is an enum or generator.
pub fn expand_aggregate<'tcx>(
mut lhs: Place<'tcx>,
orig_lhs: Place<'tcx>,
operands: impl Iterator<Item = (Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
kind: AggregateKind<'tcx>,
source_info: SourceInfo,
tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen {
let mut lhs = orig_lhs;
let mut set_discriminant = None;
let active_field_index = match kind {
AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
let adt_def = tcx.adt_def(adt_did);
if adt_def.is_enum() {
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
kind: StatementKind::SetDiscriminant {
place: Box::new(orig_lhs),
variant_index,
},
source_info,
});
lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
lhs = tcx.mk_place_downcast(orig_lhs, adt_def, variant_index);
}
active_field_index
}
@ -38,7 +42,7 @@ pub fn expand_aggregate<'tcx>(
// variant 0 (Unresumed).
let variant_index = VariantIdx::new(0);
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
kind: StatementKind::SetDiscriminant { place: Box::new(orig_lhs), variant_index },
source_info,
});
@ -50,27 +54,24 @@ pub fn expand_aggregate<'tcx>(
_ => None,
};
operands
.enumerate()
.map(move |(i, (op, ty))| {
let lhs_field = if let AggregateKind::Array(_) = kind {
let offset = u64::try_from(i).unwrap();
tcx.mk_place_elem(
lhs,
ProjectionElem::ConstantIndex {
offset,
min_length: offset + 1,
from_end: false,
},
)
} else {
let field = Field::new(active_field_index.unwrap_or(i));
tcx.mk_place_field(lhs, field, ty)
};
Statement {
source_info,
kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
}
})
let operands = operands.enumerate().map(move |(i, (op, ty))| {
let lhs_field = if let AggregateKind::Array(_) = kind {
let offset = u64::try_from(i).unwrap();
tcx.mk_place_elem(
lhs,
ProjectionElem::ConstantIndex { offset, min_length: offset + 1, from_end: false },
)
} else {
let field = Field::new(active_field_index.unwrap_or(i));
tcx.mk_place_field(lhs, field, ty)
};
Statement {
source_info,
kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
}
});
[Statement { source_info, kind: StatementKind::Deinit(Box::new(orig_lhs)) }]
.into_iter()
.chain(operands)
.chain(set_discriminant)
}