Add new Deinit
statement kind
This commit is contained in:
parent
d00e77078c
commit
9b6b1a625b
27 changed files with 141 additions and 66 deletions
|
@ -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> {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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(_)
|
||||
|
|
|
@ -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(_, _) => {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue