Skip to content

Commit 98265d3

Browse files
committed
Convert Drop statement into terminator
The structure of the old translator as well as MIR assumed that drop glue cannot possibly panic and translated the drops accordingly. However, in presence of `Drop::drop` this assumption can be trivially shown to be untrue. As such, the Rust code like the following would never print number 2: ```rust struct Droppable(u32); impl Drop for Droppable { fn drop(&mut self) { if self.0 == 1 { panic!("Droppable(1)") } else { println!("{}", self.0) } } } fn main() { let x = Droppable(2); let y = Droppable(1); } ``` While the behaviour is allowed according to the language rules (we allow drops to not run), that’s a very counter-intuitive behaviour. We fix this in MIR by allowing `Drop` to have a target to take on divergence and connect the drops in such a way so the leftover drops are executed when some drop unwinds. Note, that this commit still does not implement the translator part of changes necessary for the grand scheme of things to fully work, so the actual observed behaviour does not change yet. Coming soon™. See rust-lang#14875.
1 parent 65dd5e6 commit 98265d3

File tree

9 files changed

+309
-161
lines changed

9 files changed

+309
-161
lines changed

src/librustc/mir/repr.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,13 @@ pub enum Terminator<'tcx> {
262262
/// `END_BLOCK`.
263263
Return,
264264

265+
/// Drop the Lvalue
266+
Drop {
267+
value: Lvalue<'tcx>,
268+
target: BasicBlock,
269+
unwind: Option<BasicBlock>
270+
},
271+
265272
/// Block ends with a call of a converging function
266273
Call {
267274
/// The function that’s being called
@@ -290,6 +297,8 @@ impl<'tcx> Terminator<'tcx> {
290297
slice::ref_slice(t).into_cow(),
291298
Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(),
292299
Call { destination: None, cleanup: None, .. } => (&[]).into_cow(),
300+
Drop { target, unwind: Some(unwind), .. } => vec![target, unwind].into_cow(),
301+
Drop { ref target, .. } => slice::ref_slice(target).into_cow(),
293302
}
294303
}
295304

@@ -308,6 +317,8 @@ impl<'tcx> Terminator<'tcx> {
308317
Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t],
309318
Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c],
310319
Call { destination: None, cleanup: None, .. } => vec![],
320+
Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind],
321+
Drop { ref mut target, .. } => vec![target]
311322
}
312323
}
313324
}
@@ -374,6 +385,7 @@ impl<'tcx> Terminator<'tcx> {
374385
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
375386
Return => write!(fmt, "return"),
376387
Resume => write!(fmt, "resume"),
388+
Drop { ref value, .. } => write!(fmt, "drop({:?})", value),
377389
Call { ref func, ref args, ref destination, .. } => {
378390
if let Some((ref destination, _)) = *destination {
379391
try!(write!(fmt, "{:?} = ", destination));
@@ -418,6 +430,8 @@ impl<'tcx> Terminator<'tcx> {
418430
Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()],
419431
Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()],
420432
Call { destination: None, cleanup: None, .. } => vec![],
433+
Drop { unwind: None, .. } => vec!["return".into_cow()],
434+
Drop { .. } => vec!["return".into_cow(), "unwind".into_cow()],
421435
}
422436
}
423437
}
@@ -435,15 +449,13 @@ pub struct Statement<'tcx> {
435449
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
436450
pub enum StatementKind<'tcx> {
437451
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
438-
Drop(Lvalue<'tcx>),
439452
}
440453

441454
impl<'tcx> Debug for Statement<'tcx> {
442455
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
443456
use self::StatementKind::*;
444457
match self.kind {
445-
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
446-
Drop(ref lv) => write!(fmt, "drop {:?}", lv),
458+
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv)
447459
}
448460
}
449461
}

src/librustc/mir/visit.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,6 @@ macro_rules! make_mir_visitor {
124124
ref $($mutability)* rvalue) => {
125125
self.visit_assign(block, lvalue, rvalue);
126126
}
127-
StatementKind::Drop(ref $($mutability)* lvalue) => {
128-
self.visit_lvalue(lvalue, LvalueContext::Drop);
129-
}
130127
}
131128
}
132129

@@ -177,10 +174,16 @@ macro_rules! make_mir_visitor {
177174
Terminator::Return => {
178175
}
179176

177+
Terminator::Drop { ref $($mutability)* value, target, unwind } => {
178+
self.visit_lvalue(value, LvalueContext::Drop);
179+
self.visit_branch(block, target);
180+
unwind.map(|t| self.visit_branch(block, t));
181+
}
182+
180183
Terminator::Call { ref $($mutability)* func,
181184
ref $($mutability)* args,
182185
ref $($mutability)* destination,
183-
ref $($mutability)* cleanup } => {
186+
cleanup } => {
184187
self.visit_operand(func);
185188
for arg in args {
186189
self.visit_operand(arg);

src/librustc_mir/build/cfg.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,6 @@ impl<'tcx> CFG<'tcx> {
4343
self.block_data_mut(block).statements.push(statement);
4444
}
4545

46-
pub fn push_drop(&mut self, block: BasicBlock, span: Span, lvalue: &Lvalue<'tcx>) {
47-
self.push(block, Statement {
48-
span: span,
49-
kind: StatementKind::Drop(lvalue.clone())
50-
});
51-
}
52-
5346
pub fn push_assign(&mut self,
5447
block: BasicBlock,
5548
span: Span,

src/librustc_mir/build/expr/into.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
188188
// operators like x[j] = x[i].
189189
let rhs = unpack!(block = this.as_operand(block, rhs));
190190
let lhs = unpack!(block = this.as_lvalue(block, lhs));
191-
this.cfg.push_drop(block, expr_span, &lhs);
191+
unpack!(block = this.build_drop(block, lhs.clone()));
192192
this.cfg.push_assign(block, expr_span, &lhs, Rvalue::Use(rhs));
193193
block.unit()
194194
}

0 commit comments

Comments
 (0)