Skip to content

Commit a147703

Browse files
committed
[MIR] Implement zero-on-move
Also fix the tests to catch the double-drop on move.
1 parent 569b18f commit a147703

File tree

5 files changed

+62
-28
lines changed

5 files changed

+62
-28
lines changed

src/librustc_trans/trans/mir/drop.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use trans::machine;
2121
use trans::type_of;
2222
use trans::type_::Type;
2323

24-
use super::MirContext;
24+
use super::{MirContext, TempRef};
2525

2626
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
2727
pub fn trans_drop(&mut self,
@@ -78,4 +78,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
7878
let align = common::C_u32(bcx.ccx(), machine::llalign_of_min(bcx.ccx(), llty));
7979
base::call_memset(&build::B(bcx), llptr, filling, size, align, false);
8080
}
81+
82+
pub fn set_operand_dropped(&mut self,
83+
bcx: Block<'bcx, 'tcx>,
84+
operand: &mir::Operand<'tcx>) {
85+
match *operand {
86+
mir::Operand::Constant(_) => return,
87+
mir::Operand::Consume(ref lvalue) => {
88+
if let mir::Lvalue::Temp(idx) = *lvalue {
89+
if let TempRef::Operand(..) = self.temps[idx as usize] {
90+
return // we do not handle these, should we?
91+
}
92+
}
93+
let lvalue = self.trans_lvalue(bcx, lvalue);
94+
let ty = lvalue.ty.to_ty(bcx.tcx());
95+
if !glue::type_needs_drop(bcx.tcx(), ty) ||
96+
common::type_is_fat_ptr(bcx.tcx(), ty) {
97+
return
98+
} else {
99+
self.drop_fill(bcx, lvalue.llval, ty);
100+
}
101+
}
102+
}
103+
}
81104
}

src/librustc_trans/trans/mir/rvalue.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
4343
rvalue);
4444

4545
match *rvalue {
46+
mir::Rvalue::Use(ref operand) => {
47+
// FIXME: consider not copying constants through stack. (fixable by translating
48+
// constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
49+
let tr_operand = self.trans_operand(bcx, operand);
50+
self.store_operand(bcx, dest.llval, tr_operand);
51+
self.set_operand_dropped(bcx, operand);
52+
bcx
53+
}
54+
4655
mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => {
4756
if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
4857
// into-coerce of a thin pointer to a fat pointer - just
@@ -162,13 +171,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
162171
assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
163172

164173
match *rvalue {
165-
mir::Rvalue::Use(ref operand) => {
166-
// FIXME: consider not copying constants through stack. (fixable by translating
167-
// constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
168-
let operand = self.trans_operand(bcx, operand);
169-
(bcx, operand)
170-
}
171-
172174
mir::Rvalue::Cast(ref kind, ref operand, cast_ty) => {
173175
let operand = self.trans_operand(bcx, operand);
174176
debug!("cast operand is {}", operand.repr(bcx));
@@ -398,6 +400,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
398400
})
399401
}
400402

403+
mir::Rvalue::Use(..) |
401404
mir::Rvalue::Repeat(..) |
402405
mir::Rvalue::Aggregate(..) |
403406
mir::Rvalue::Slice { .. } |
@@ -508,14 +511,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
508511

509512
pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
510513
match *rvalue {
511-
mir::Rvalue::Use(..) | // (*)
512514
mir::Rvalue::Ref(..) |
513515
mir::Rvalue::Len(..) |
514516
mir::Rvalue::Cast(..) | // (*)
515517
mir::Rvalue::BinaryOp(..) |
516518
mir::Rvalue::UnaryOp(..) |
517519
mir::Rvalue::Box(..) =>
518520
true,
521+
mir::Rvalue::Use(..) | // (**)
519522
mir::Rvalue::Repeat(..) |
520523
mir::Rvalue::Aggregate(..) |
521524
mir::Rvalue::Slice { .. } |
@@ -524,4 +527,6 @@ pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool {
524527
}
525528

526529
// (*) this is only true if the type is suitable
530+
// (**) we need to zero-out the old value before moving, so we are restricted to either
531+
// ensuring all users of `Use` set it themselves or not allowing to “create” operand for it.
527532
}

src/test/run-fail/mir_dynamic_drops_1.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,24 @@ use std::io::{self, Write};
1414

1515

1616
/// Structure which will not allow to be dropped twice.
17-
struct Droppable(bool, u32);
18-
impl Drop for Droppable {
17+
struct Droppable<'a>(&'a mut bool, u32);
18+
impl<'a> Drop for Droppable<'a> {
1919
fn drop(&mut self) {
20-
if self.0 {
20+
if *self.0 {
2121
writeln!(io::stderr(), "{} dropped twice", self.1);
2222
::std::process::exit(1);
2323
}
2424
writeln!(io::stderr(), "drop {}", self.1);
25-
self.0 = true;
25+
*self.0 = true;
2626
}
2727
}
2828

2929
#[rustc_mir]
3030
fn mir(){
31-
let x = Droppable(false, 1);
32-
let y = Droppable(false, 2);
31+
let mut b1 = false;
32+
let mut b2 = false;
33+
let x = Droppable(&mut b1, 1);
34+
let y = Droppable(&mut b2, 2);
3335
let mut z = x;
3436
let k = y;
3537
z = k;

src/test/run-fail/mir_dynamic_drops_2.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ use std::io::{self, Write};
1313

1414

1515
/// Structure which will not allow to be dropped twice.
16-
struct Droppable(bool, u32);
17-
impl Drop for Droppable {
16+
struct Droppable<'a>(&'a mut bool, u32);
17+
impl<'a> Drop for Droppable<'a> {
1818
fn drop(&mut self) {
19-
if self.0 {
19+
if *self.0 {
2020
writeln!(io::stderr(), "{} dropped twice", self.1);
2121
::std::process::exit(1);
2222
}
2323
writeln!(io::stderr(), "drop {}", self.1);
24-
self.0 = true;
24+
*self.0 = true;
2525
}
2626
}
2727

@@ -34,6 +34,7 @@ fn mir(d: Droppable){
3434
}
3535

3636
fn main() {
37-
mir(Droppable(false, 1));
37+
let mut d1 = false;
38+
mir(Droppable(&mut d1, 1));
3839
panic!();
3940
}

src/test/run-fail/mir_dynamic_drops_3.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,31 @@ use std::io::{self, Write};
1616

1717

1818
/// Structure which will not allow to be dropped twice.
19-
struct Droppable(bool, u32);
20-
impl Drop for Droppable {
19+
struct Droppable<'a>(&'a mut bool, u32);
20+
impl<'a> Drop for Droppable<'a> {
2121
fn drop(&mut self) {
22-
if self.0 {
22+
if *self.0 {
2323
writeln!(io::stderr(), "{} dropped twice", self.1);
2424
::std::process::exit(1);
2525
}
2626
writeln!(io::stderr(), "drop {}", self.1);
27-
self.0 = true;
27+
*self.0 = true;
2828
}
2929
}
3030

31-
fn may_panic() -> Droppable {
31+
fn may_panic<'a>() -> Droppable<'a> {
3232
panic!("unwind happens");
3333
}
3434

3535
#[rustc_mir]
3636
fn mir(d: Droppable){
37-
let y = Droppable(false, 2);
38-
let x = [Droppable(false, 1), y, d, may_panic()];
37+
let mut d1 = false;
38+
let mut d2 = false;
39+
let y = Droppable(&mut d2, 2);
40+
let x = [Droppable(&mut d1, 1), y, d, may_panic()];
3941
}
4042

4143
fn main() {
42-
mir(Droppable(false, 3));
44+
let mut d3 = false;
45+
mir(Droppable(&mut d3, 3));
4346
}

0 commit comments

Comments
 (0)