mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 14:01:51 +00:00
Add new Deinit
statement kind
This commit is contained in:
parent
d00e77078c
commit
9b6b1a625b
@ -386,6 +386,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
|
||||
mir::StatementKind::FakeRead(..)
|
||||
| mir::StatementKind::SetDiscriminant { .. }
|
||||
| mir::StatementKind::Deinit(..)
|
||||
| mir::StatementKind::StorageLive(..)
|
||||
| mir::StatementKind::Retag { .. }
|
||||
| mir::StatementKind::AscribeUserType(..)
|
||||
|
@ -63,9 +63,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
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,
|
||||
@ -91,6 +88,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
LocalMutationIsAllowed::Yes,
|
||||
);
|
||||
}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
}
|
||||
}
|
||||
|
||||
self.super_statement(statement, location);
|
||||
|
@ -626,9 +626,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||
self.mutate_place(location, (**place, span), Shallow(None), flow_state);
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
..
|
||||
}) => {
|
||||
@ -654,6 +651,9 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1303,28 +1303,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
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(
|
||||
@ -1358,6 +1336,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Nop => {}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,6 +772,7 @@ fn codegen_stmt<'tcx>(
|
||||
}
|
||||
StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Deinit(_)
|
||||
| StatementKind::Nop
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::Retag { .. }
|
||||
|
@ -518,6 +518,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
StatementKind::Assign(_)
|
||||
| StatementKind::FakeRead(_)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(_)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
|
@ -48,6 +48,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
.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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -1590,6 +1590,8 @@ pub enum StatementKind<'tcx> {
|
||||
/// 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),
|
||||
|
||||
@ -1739,6 +1741,7 @@ impl Debug for Statement<'_> {
|
||||
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)
|
||||
}
|
||||
|
@ -243,6 +243,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
|
||||
Assign(..) => "Assign",
|
||||
FakeRead(..) => "FakeRead",
|
||||
SetDiscriminant { .. } => "SetDiscriminant",
|
||||
Deinit(..) => "Deinit",
|
||||
StorageLive(..) => "StorageLive",
|
||||
StorageDead(..) => "StorageDead",
|
||||
Retag(..) => "Retag",
|
||||
|
@ -399,6 +399,13 @@ macro_rules! make_mir_visitor {
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::Deinit(place) => {
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
)
|
||||
}
|
||||
StatementKind::StorageLive(local) => {
|
||||
self.visit_local(
|
||||
local,
|
||||
|
@ -131,7 +131,8 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -296,10 +296,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
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 { .. }
|
||||
|
@ -97,6 +97,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||
StatementKind::Assign(..)
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::Retag { .. }
|
||||
|
@ -827,6 +827,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Assign(_)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _) => {
|
||||
Some(statement.source_info.span)
|
||||
|
@ -530,6 +530,7 @@ impl<'a> Conflicts<'a> {
|
||||
StatementKind::Assign(_) => {}
|
||||
|
||||
StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::Retag(..)
|
||||
|
@ -1441,6 +1441,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||
|
||||
StatementKind::FakeRead(..)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(..)
|
||||
|
@ -50,6 +50,7 @@ impl RemoveNoopLandingPads {
|
||||
|
||||
StatementKind::Assign { .. }
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Retag { .. } => {
|
||||
return false;
|
||||
|
@ -21,7 +21,9 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
|
||||
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;
|
||||
|
@ -242,6 +242,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
|
||||
// These statements have no influence on the place
|
||||
// we are interested in
|
||||
StatementKind::FakeRead(_)
|
||||
| StatementKind::Deinit(_)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _)
|
||||
@ -308,6 +309,7 @@ fn find_determining_place<'tcx>(
|
||||
// These statements have no influence on the place
|
||||
// we are interested in
|
||||
StatementKind::FakeRead(_)
|
||||
| StatementKind::Deinit(_)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
|
@ -498,7 +498,8 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -534,9 +535,8 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
|
||||
}
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -211,7 +211,8 @@ fn check_statement<'tcx>(
|
||||
|
||||
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)?;
|
||||
|
Loading…
Reference in New Issue
Block a user