mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
introduce DropAndReplace for translating assignments
this introduces a DropAndReplace terminator as a fix to #30380. That terminator is suppsoed to be translated by desugaring during drop elaboration, which is not implemented in this commit, so this breaks `-Z orbit` temporarily.
This commit is contained in:
parent
95206f438f
commit
de7cb0fdd6
@ -330,11 +330,19 @@ pub enum TerminatorKind<'tcx> {
|
||||
|
||||
/// Drop the Lvalue
|
||||
Drop {
|
||||
value: Lvalue<'tcx>,
|
||||
location: Lvalue<'tcx>,
|
||||
target: BasicBlock,
|
||||
unwind: Option<BasicBlock>
|
||||
},
|
||||
|
||||
/// Drop the Lvalue and assign the new value over it
|
||||
DropAndReplace {
|
||||
location: Lvalue<'tcx>,
|
||||
value: Operand<'tcx>,
|
||||
target: BasicBlock,
|
||||
unwind: Option<BasicBlock>,
|
||||
},
|
||||
|
||||
/// Block ends with a call of a converging function
|
||||
Call {
|
||||
/// The function that’s being called
|
||||
@ -373,8 +381,14 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
slice::ref_slice(t).into_cow(),
|
||||
Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(),
|
||||
Call { destination: None, cleanup: None, .. } => (&[]).into_cow(),
|
||||
Drop { target, unwind: Some(unwind), .. } => vec![target, unwind].into_cow(),
|
||||
Drop { ref target, .. } => slice::ref_slice(target).into_cow(),
|
||||
DropAndReplace { target, unwind: Some(unwind), .. } |
|
||||
Drop { target, unwind: Some(unwind), .. } => {
|
||||
vec![target, unwind].into_cow()
|
||||
}
|
||||
DropAndReplace { ref target, unwind: None, .. } |
|
||||
Drop { ref target, unwind: None, .. } => {
|
||||
slice::ref_slice(target).into_cow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,8 +407,12 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t],
|
||||
Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c],
|
||||
Call { destination: None, cleanup: None, .. } => vec![],
|
||||
DropAndReplace { ref mut target, unwind: Some(ref mut unwind), .. } |
|
||||
Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind],
|
||||
Drop { ref mut target, .. } => vec![target]
|
||||
DropAndReplace { ref mut target, unwind: None, .. } |
|
||||
Drop { ref mut target, unwind: None, .. } => {
|
||||
vec![target]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -461,7 +479,9 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
||||
Return => write!(fmt, "return"),
|
||||
Resume => write!(fmt, "resume"),
|
||||
Drop { ref value, .. } => write!(fmt, "drop({:?})", value),
|
||||
Drop { ref location, .. } => write!(fmt, "drop({:?})", location),
|
||||
DropAndReplace { ref location, ref value, .. } =>
|
||||
write!(fmt, "replace({:?} <- {:?})", location, value),
|
||||
Call { ref func, ref args, ref destination, .. } => {
|
||||
if let Some((ref destination, _)) = *destination {
|
||||
write!(fmt, "{:?} = ", destination)?;
|
||||
@ -506,8 +526,12 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()],
|
||||
Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()],
|
||||
Call { destination: None, cleanup: None, .. } => vec![],
|
||||
DropAndReplace { unwind: None, .. } |
|
||||
Drop { unwind: None, .. } => vec!["return".into_cow()],
|
||||
Drop { .. } => vec!["return".into_cow(), "unwind".into_cow()],
|
||||
DropAndReplace { unwind: Some(_), .. } |
|
||||
Drop { unwind: Some(_), .. } => {
|
||||
vec!["return".into_cow(), "unwind".into_cow()]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -394,10 +394,20 @@ macro_rules! make_mir_visitor {
|
||||
TerminatorKind::Return => {
|
||||
}
|
||||
|
||||
TerminatorKind::Drop { ref $($mutability)* value,
|
||||
TerminatorKind::Drop { ref $($mutability)* location,
|
||||
target,
|
||||
unwind } => {
|
||||
self.visit_lvalue(value, LvalueContext::Drop);
|
||||
self.visit_lvalue(location, LvalueContext::Drop);
|
||||
self.visit_branch(block, target);
|
||||
unwind.map(|t| self.visit_branch(block, t));
|
||||
}
|
||||
|
||||
TerminatorKind::DropAndReplace { ref $($mutability)* location,
|
||||
ref $($mutability)* value,
|
||||
target,
|
||||
unwind } => {
|
||||
self.visit_lvalue(location, LvalueContext::Drop);
|
||||
self.visit_operand(value);
|
||||
self.visit_branch(block, target);
|
||||
unwind.map(|t| self.visit_branch(block, t));
|
||||
}
|
||||
|
@ -444,10 +444,17 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
|
||||
repr::TerminatorKind::Return |
|
||||
repr::TerminatorKind::Resume => {}
|
||||
repr::TerminatorKind::Goto { ref target } |
|
||||
repr::TerminatorKind::Drop { ref target, value: _, unwind: None } => {
|
||||
repr::TerminatorKind::Drop { ref target, location: _, unwind: None } |
|
||||
|
||||
repr::TerminatorKind::DropAndReplace {
|
||||
ref target, value: _, location: _, unwind: None
|
||||
} => {
|
||||
self.propagate_bits_into_entry_set_for(in_out, changed, target);
|
||||
}
|
||||
repr::TerminatorKind::Drop { ref target, value: _, unwind: Some(ref unwind) } => {
|
||||
repr::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } |
|
||||
repr::TerminatorKind::DropAndReplace {
|
||||
ref target, value: _, location: _, unwind: Some(ref unwind)
|
||||
} => {
|
||||
self.propagate_bits_into_entry_set_for(in_out, changed, target);
|
||||
self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
|
||||
}
|
||||
|
@ -671,10 +671,18 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
|
||||
let _ = discr;
|
||||
}
|
||||
|
||||
TerminatorKind::Drop { value: ref lval, target: _, unwind: _ } => {
|
||||
TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
|
||||
let source = Location { block: bb,
|
||||
index: bb_data.statements.len() };
|
||||
bb_ctxt.on_move_out_lval(SK::Drop, lval, source);
|
||||
bb_ctxt.on_move_out_lval(SK::Drop, location, source);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
|
||||
let assigned_path = bb_ctxt.builder.move_path_for(location);
|
||||
bb_ctxt.path_map.fill_to(assigned_path.idx());
|
||||
|
||||
let source = Location { block: bb,
|
||||
index: bb_data.statements.len() };
|
||||
bb_ctxt.on_operand(SK::Use, value, source);
|
||||
}
|
||||
TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
|
||||
let source = Location { block: bb,
|
||||
|
@ -309,15 +309,23 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
|
||||
Some(stmt) => match stmt.kind {
|
||||
repr::StatementKind::Assign(ref lvalue, _) => {
|
||||
debug!("drop_flag_effects: assignment {:?}", stmt);
|
||||
on_all_children_bits(tcx, mir, move_data,
|
||||
on_all_children_bits(tcx, mir, move_data,
|
||||
move_data.rev_lookup.find(lvalue),
|
||||
|moi| callback(moi, DropFlagState::Present))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// terminator - no move-ins except for function return edge
|
||||
let term = bb.terminator();
|
||||
debug!("drop_flag_effects: terminator {:?}", term);
|
||||
debug!("drop_flag_effects: replace {:?}", bb.terminator());
|
||||
match bb.terminator().kind {
|
||||
repr::TerminatorKind::DropAndReplace { ref location, .. } => {
|
||||
on_all_children_bits(tcx, mir, move_data,
|
||||
move_data.rev_lookup.find(location),
|
||||
|moi| callback(moi, DropFlagState::Present))
|
||||
}
|
||||
_ => {
|
||||
// other terminators do not contain move-ins
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,29 +34,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let scope_id = this.innermost_scope_id();
|
||||
let lhs_span = lhs.span;
|
||||
|
||||
let lhs_ty = lhs.ty;
|
||||
let rhs_ty = rhs.ty;
|
||||
|
||||
let lhs_needs_drop = this.hir.needs_drop(lhs_ty);
|
||||
let rhs_needs_drop = this.hir.needs_drop(rhs_ty);
|
||||
|
||||
// Note: we evaluate assignments right-to-left. This
|
||||
// is better for borrowck interaction with overloaded
|
||||
// operators like x[j] = x[i].
|
||||
|
||||
// Generate better code for things that don't need to be
|
||||
// dropped.
|
||||
let rhs = if lhs_needs_drop || rhs_needs_drop {
|
||||
let op = unpack!(block = this.as_operand(block, rhs));
|
||||
Rvalue::Use(op)
|
||||
if this.hir.needs_drop(lhs.ty) {
|
||||
let rhs = unpack!(block = this.as_operand(block, rhs));
|
||||
let lhs = unpack!(block = this.as_lvalue(block, lhs));
|
||||
unpack!(block = this.build_drop_and_replace(
|
||||
block, lhs_span, lhs, rhs
|
||||
));
|
||||
block.unit()
|
||||
} else {
|
||||
unpack!(block = this.as_rvalue(block, rhs))
|
||||
};
|
||||
|
||||
let lhs = unpack!(block = this.as_lvalue(block, lhs));
|
||||
unpack!(block = this.build_drop(block, lhs_span, lhs.clone(), lhs_ty));
|
||||
this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs);
|
||||
block.unit()
|
||||
let rhs = unpack!(block = this.as_rvalue(block, rhs));
|
||||
let lhs = unpack!(block = this.as_lvalue(block, lhs));
|
||||
this.cfg.push_assign(block, scope_id, expr_span, &lhs, rhs);
|
||||
block.unit()
|
||||
}
|
||||
}
|
||||
ExprKind::AssignOp { op, lhs, rhs } => {
|
||||
// FIXME(#28160) there is an interesting semantics
|
||||
|
@ -139,7 +139,7 @@ struct DropData<'tcx> {
|
||||
span: Span,
|
||||
|
||||
/// lvalue to drop
|
||||
value: Lvalue<'tcx>,
|
||||
location: Lvalue<'tcx>,
|
||||
|
||||
/// The cached block for the cleanups-on-diverge path. This block
|
||||
/// contains code to run the current drop and all the preceding
|
||||
@ -402,7 +402,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// the drop that comes before it in the vector.
|
||||
scope.drops.push(DropData {
|
||||
span: span,
|
||||
value: lvalue.clone(),
|
||||
location: lvalue.clone(),
|
||||
cached_block: None
|
||||
});
|
||||
return;
|
||||
@ -497,7 +497,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
pub fn build_drop(&mut self,
|
||||
block: BasicBlock,
|
||||
span: Span,
|
||||
value: Lvalue<'tcx>,
|
||||
location: Lvalue<'tcx>,
|
||||
ty: Ty<'tcx>) -> BlockAnd<()> {
|
||||
if !self.hir.needs_drop(ty) {
|
||||
return block.unit();
|
||||
@ -509,7 +509,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
scope_id,
|
||||
span,
|
||||
TerminatorKind::Drop {
|
||||
value: value,
|
||||
location: location,
|
||||
target: next_target,
|
||||
unwind: diverge_target,
|
||||
});
|
||||
@ -517,6 +517,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn build_drop_and_replace(&mut self,
|
||||
block: BasicBlock,
|
||||
span: Span,
|
||||
location: Lvalue<'tcx>,
|
||||
value: Operand<'tcx>) -> BlockAnd<()> {
|
||||
let scope_id = self.innermost_scope_id();
|
||||
let next_target = self.cfg.start_new_block();
|
||||
let diverge_target = self.diverge_cleanup();
|
||||
self.cfg.terminate(block,
|
||||
scope_id,
|
||||
span,
|
||||
TerminatorKind::DropAndReplace {
|
||||
location: location,
|
||||
value: value,
|
||||
target: next_target,
|
||||
unwind: diverge_target,
|
||||
});
|
||||
next_target.unit()
|
||||
}
|
||||
|
||||
// Panicking
|
||||
// =========
|
||||
// FIXME: should be moved into their own module
|
||||
@ -653,7 +674,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
|
||||
});
|
||||
let next = cfg.start_new_block();
|
||||
cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop {
|
||||
value: drop_data.value.clone(),
|
||||
location: drop_data.location.clone(),
|
||||
target: next,
|
||||
unwind: on_diverge
|
||||
});
|
||||
@ -709,7 +730,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
scope.id,
|
||||
drop_data.span,
|
||||
TerminatorKind::Drop {
|
||||
value: drop_data.value.clone(),
|
||||
location: drop_data.location.clone(),
|
||||
target: target,
|
||||
unwind: None
|
||||
});
|
||||
|
@ -105,7 +105,9 @@ impl Pass for BreakCleanupEdges {}
|
||||
fn term_is_invoke(term: &Terminator) -> bool {
|
||||
match term.kind {
|
||||
TerminatorKind::Call { cleanup: Some(_), .. } |
|
||||
TerminatorKind::Drop { unwind: Some(_), .. } => true,
|
||||
// FIXME: not sure whether we need this one
|
||||
TerminatorKind::Drop { unwind: Some(_), .. } |
|
||||
TerminatorKind::DropAndReplace { .. } => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
@ -29,12 +29,11 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
||||
TerminatorKind::SwitchInt { .. } => {
|
||||
/* nothing to do */
|
||||
},
|
||||
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
|
||||
TerminatorKind::DropAndReplace { ref mut unwind, .. } |
|
||||
TerminatorKind::Drop { ref mut unwind, .. } => {
|
||||
unwind.take();
|
||||
},
|
||||
TerminatorKind::Call { ref mut cleanup, .. } => {
|
||||
cleanup.take();
|
||||
},
|
||||
}
|
||||
self.super_terminator(bb, terminator);
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
});
|
||||
let terminator = block.terminator_mut();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { value: Lvalue::Temp(index), target, .. } => {
|
||||
TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => {
|
||||
if promoted(index) {
|
||||
terminator.kind = TerminatorKind::Goto {
|
||||
target: target
|
||||
|
@ -422,6 +422,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
||||
|
||||
TerminatorKind::Switch {..} |
|
||||
TerminatorKind::SwitchInt {..} |
|
||||
TerminatorKind::DropAndReplace { .. } |
|
||||
TerminatorKind::Resume => None,
|
||||
|
||||
TerminatorKind::Return => {
|
||||
|
@ -363,6 +363,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
// no checks needed for these
|
||||
}
|
||||
|
||||
|
||||
TerminatorKind::DropAndReplace {
|
||||
ref location,
|
||||
ref value,
|
||||
..
|
||||
} => {
|
||||
let lv_ty = mir.lvalue_ty(tcx, location).to_ty(tcx);
|
||||
let rv_ty = mir.operand_ty(tcx, value);
|
||||
if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
|
||||
span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
|
||||
lv_ty, rv_ty, terr);
|
||||
}
|
||||
}
|
||||
|
||||
TerminatorKind::If { ref cond, .. } => {
|
||||
let cond_ty = mir.operand_ty(tcx, cond);
|
||||
match cond_ty.sty {
|
||||
|
@ -143,8 +143,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Drop { ref value, target, unwind } => {
|
||||
let lvalue = self.trans_lvalue(&bcx, value);
|
||||
mir::TerminatorKind::Drop { ref location, target, unwind } => {
|
||||
let lvalue = self.trans_lvalue(&bcx, location);
|
||||
let ty = lvalue.ty.to_ty(bcx.tcx());
|
||||
// Double check for necessity to drop
|
||||
if !glue::type_needs_drop(bcx.tcx(), ty) {
|
||||
@ -177,6 +177,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
mir::TerminatorKind::DropAndReplace { .. } => {
|
||||
bug!("undesugared DropAndReplace in trans: {:?}", data);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Call { ref func, ref args, ref destination, ref cleanup } => {
|
||||
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
|
||||
let callee = self.trans_operand(&bcx, func);
|
||||
|
Loading…
Reference in New Issue
Block a user