mir::StatementKind::FakeRead(..)
| mir::StatementKind::SetDiscriminant { .. }
+ | mir::StatementKind::Deinit(..)
| mir::StatementKind::StorageLive(..)
| mir::StatementKind::Retag { .. }
| mir::StatementKind::AscribeUserType(..)
StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
- StatementKind::SetDiscriminant { place, variant_index: _ } => {
- self.mutate_place(location, **place, Shallow(None));
- }
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
ref src,
ref dst,
LocalMutationIsAllowed::Yes,
);
}
+ StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ bug!("Statement not allowed in this MIR phase")
+ }
}
self.super_statement(statement, location);
flow_state,
);
}
- StatementKind::SetDiscriminant { place, variant_index: _ } => {
- self.mutate_place(location, (**place, span), Shallow(None), flow_state);
- }
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
..
}) => {
flow_state,
);
}
+ StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ bug!("Statement not allowed in this MIR phase")
+ }
}
}
);
}
}
- StatementKind::SetDiscriminant { ref place, variant_index } => {
- let place_type = place.ty(body, tcx).ty;
- let adt = match place_type.kind() {
- ty::Adt(adt, _) if adt.is_enum() => adt,
- _ => {
- span_bug!(
- stmt.source_info.span,
- "bad set discriminant ({:?} = {:?}): lhs is not an enum",
- place,
- variant_index
- );
- }
- };
- if variant_index.as_usize() >= adt.variants().len() {
- span_bug!(
- stmt.source_info.span,
- "bad set discriminant ({:?} = {:?}): value of of range",
- place,
- variant_index
- );
- };
- }
StatementKind::AscribeUserType(box (ref place, ref projection), variance) => {
let place_ty = place.ty(body, tcx).ty;
if let Err(terr) = self.relate_type_and_user_type(
| StatementKind::Retag { .. }
| StatementKind::Coverage(..)
| StatementKind::Nop => {}
+ StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ bug!("Statement not allowed in this MIR phase")
+ }
}
}
}
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
+ | StatementKind::Deinit(_)
| StatementKind::Nop
| StatementKind::FakeRead(..)
| StatementKind::Retag { .. }
StatementKind::Assign(_)
| StatementKind::FakeRead(_)
| StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(_)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag(_, _)
.codegen_set_discr(&mut bx, variant_index);
bx
}
+ mir::StatementKind::Deinit(..) => {
+ // For now, don't codegen this to anything. In the future it may be worth
+ // experimenting with what kind of information we can emit to LLVM without hurting
+ // perf here
+ bx
+ }
mir::StatementKind::StorageLive(local) => {
if let LocalRef::Place(cg_place) = self.locals[local] {
cg_place.storage_live(&mut bx);
) -> 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> {
}
}
+ 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)]
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)?;
match statement.kind {
StatementKind::Assign(..)
| StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(..)
| StatementKind::FakeRead(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
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(_, _) => {
/// (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
}
// 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,
});
_ => 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)
}
/// Write the discriminant for a variant to the enum Place.
SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
+ Deinit(Box<Place<'tcx>>),
+
/// Start a live range for the storage of the local.
StorageLive(Local),
SetDiscriminant { ref place, variant_index } => {
write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
}
+ Deinit(ref place) => write!(fmt, "Deinit({:?})", place),
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}
Assign(..) => "Assign",
FakeRead(..) => "FakeRead",
SetDiscriminant { .. } => "SetDiscriminant",
+ Deinit(..) => "Deinit",
StorageLive(..) => "StorageLive",
StorageDead(..) => "StorageDead",
Retag(..) => "Retag",
location
);
}
+ StatementKind::Deinit(place) => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::Store),
+ location
+ )
+ }
StatementKind::StorageLive(local) => {
self.visit_local(
local,
// If a place is assigned to in a statement, it needs storage for that statement.
StatementKind::Assign(box (place, _))
- | StatementKind::SetDiscriminant { box place, .. } => {
+ | StatementKind::SetDiscriminant { box place, .. }
+ | StatementKind::Deinit(box place) => {
trans.gen(place.local);
}
StatementKind::StorageDead(local) => {
self.gather_move(Place::from(*local));
}
- StatementKind::SetDiscriminant { .. } => {
+ StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => {
span_bug!(
stmt.source_info.span,
- "SetDiscriminant should not exist during borrowck"
+ "SetDiscriminant/Deinit should not exist during borrowck"
);
}
StatementKind::Retag { .. }
StatementKind::Assign(..)
| StatementKind::FakeRead(..)
| StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::Retag { .. }
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Assign(_)
| StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(..)
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _) => {
Some(statement.source_info.span)
StatementKind::Assign(_) => {}
StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::Retag(..)
StatementKind::FakeRead(..)
| StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag(..)
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
+ | StatementKind::Deinit(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag { .. } => {
return false;
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for block in basic_blocks.iter_mut() {
for statement in block.statements.iter_mut() {
- if let StatementKind::Assign(box (place, _)) = statement.kind {
+ if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
+ statement.kind
+ {
let place_ty = place.ty(local_decls, tcx).ty;
if !maybe_zst(place_ty) {
continue;
// These statements have no influence on the place
// we are interested in
StatementKind::FakeRead(_)
+ | StatementKind::Deinit(_)
| StatementKind::StorageLive(_)
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _)
// These statements have no influence on the place
// we are interested in
StatementKind::FakeRead(_)
+ | StatementKind::Deinit(_)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag(_, _)
self.visit_rvalue(rvalue, location);
}
- StatementKind::SetDiscriminant { ref place, variant_index: _ } => {
+ StatementKind::SetDiscriminant { ref place, variant_index: _ }
+ | StatementKind::Deinit(ref place) => {
self.visit_lhs(place, location);
}
}
}
StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
- StatementKind::SetDiscriminant { ref place, .. } => {
- used_locals.is_used(place.local)
- }
+ StatementKind::SetDiscriminant { ref place, .. }
+ | StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
_ => true,
};
StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
// just an assignment
- StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
+ StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) =>
+ check_place(tcx, **place, span, body),
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
check_operand(tcx, dst, span, body)?;