From eef0734e58224e555648630ac89f216b7d29afb0 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 4 Feb 2016 19:40:28 +0200 Subject: [PATCH 1/3] Partially implement zeroing on-drop --- src/librustc_trans/trans/base.rs | 25 +++++--- src/librustc_trans/trans/mir/block.rs | 37 ++--------- src/librustc_trans/trans/mir/drop.rs | 81 +++++++++++++++++++++++++ src/librustc_trans/trans/mir/mod.rs | 1 + src/librustc_trans/trans/mir/operand.rs | 16 ----- src/librustc_trans/trans/mir/rvalue.rs | 7 +-- 6 files changed, 104 insertions(+), 63 deletions(-) create mode 100644 src/librustc_trans/trans/mir/drop.rs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 2fc585c7c795e..9ed3d2c3057d3 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1298,22 +1298,29 @@ pub fn init_zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<' fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte: u8) { let _icx = push_ctxt("memfill"); let ccx = b.ccx; - let llty = type_of::type_of(ccx, ty); - let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; - let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); - - let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key); let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to()); let llzeroval = C_u8(ccx, byte); let size = machine::llsize_of(ccx, llty); let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32); - let volatile = C_bool(ccx, false); - b.call(llintrinsicfn, - &[llptr, llzeroval, size, align, volatile], - None, None); + call_memset(b, llptr, llzeroval, size, align, false); } +pub fn call_memset<'bcx, 'tcx>(b: &Builder<'bcx, 'tcx>, + ptr: ValueRef, + fill_byte: ValueRef, + size: ValueRef, + align: ValueRef, + volatile: bool) { + let ccx = b.ccx; + let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; + let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); + let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key); + let volatile = C_bool(ccx, volatile); + b.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None, None); +} + + /// In general, when we create an scratch value in an alloca, the /// creator may not know if the block (that initializes the scratch /// with the desired value) actually dominates the cleanup associated diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 5be585c4189e1..ce772dc641479 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -20,7 +20,6 @@ use trans::common::{self, Block, LandingPad}; use trans::debuginfo::DebugLoc; use trans::Disr; use trans::foreign; -use trans::glue; use trans::type_of; use trans::type_::Type; @@ -96,35 +95,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Terminator::Drop { ref value, target, unwind } => { - let lvalue = self.trans_lvalue(bcx, value); - let ty = lvalue.ty.to_ty(bcx.tcx()); - // Double check for necessity to drop - if !glue::type_needs_drop(bcx.tcx(), ty) { - build::Br(bcx, self.llblock(target), DebugLoc::None); - return; - } - let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); - let drop_ty = glue::get_drop_glue_type(bcx.ccx(), ty); - let llvalue = if drop_ty != ty { - build::PointerCast(bcx, lvalue.llval, - type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) - } else { - lvalue.llval - }; - if let Some(unwind) = unwind { - let uwbcx = self.bcx(unwind); - let unwind = self.make_landing_pad(uwbcx); - build::Invoke(bcx, - drop_fn, - &[llvalue], - self.llblock(target), - unwind.llbb, - None, - DebugLoc::None); - } else { - build::Call(bcx, drop_fn, &[llvalue], None, DebugLoc::None); - build::Br(bcx, self.llblock(target), DebugLoc::None); - } + self.trans_drop(bcx, value, target, unwind); } mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => { @@ -287,7 +258,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - fn make_landing_pad(&mut self, cleanup: Block<'bcx, 'tcx>) -> Block<'bcx, 'tcx> { + pub fn make_landing_pad(&mut self, cleanup: Block<'bcx, 'tcx>) -> Block<'bcx, 'tcx> { let bcx = cleanup.fcx.new_block("cleanup", None); // FIXME(#30941) this doesn't handle msvc-style exceptions *bcx.lpad.borrow_mut() = Some(LandingPad::gnu()); @@ -314,11 +285,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> { + pub fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> { self.blocks[bb.index()] } - fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef { + pub fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef { self.blocks[bb.index()].llbb } } diff --git a/src/librustc_trans/trans/mir/drop.rs b/src/librustc_trans/trans/mir/drop.rs new file mode 100644 index 0000000000000..13e9840f7b8b8 --- /dev/null +++ b/src/librustc_trans/trans/mir/drop.rs @@ -0,0 +1,81 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::ValueRef; +use rustc::middle::ty::Ty; +use rustc::mir::repr as mir; +use trans::adt; +use trans::base; +use trans::build; +use trans::common::{self, Block}; +use trans::debuginfo::DebugLoc; +use trans::glue; +use trans::machine; +use trans::type_of; +use trans::type_::Type; + +use super::MirContext; + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_drop(&mut self, + bcx: Block<'bcx, 'tcx>, + value: &mir::Lvalue<'tcx>, + target: mir::BasicBlock, + unwind: Option) { + let lvalue = self.trans_lvalue(bcx, value); + let ty = lvalue.ty.to_ty(bcx.tcx()); + // Double check for necessity to drop + if !glue::type_needs_drop(bcx.tcx(), ty) { + build::Br(bcx, self.llblock(target), DebugLoc::None); + return; + } + let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); + let drop_ty = glue::get_drop_glue_type(bcx.ccx(), ty); + let llvalue = if drop_ty != ty { + build::PointerCast(bcx, lvalue.llval, + type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + } else { + lvalue.llval + }; + if let Some(unwind) = unwind { + // block cannot be cleanup in this case, so a regular block is fine + let intermediate_bcx = bcx.fcx.new_block("", None); + let uwbcx = self.bcx(unwind); + let unwind = self.make_landing_pad(uwbcx); + // FIXME: it could be possible to do zeroing before invoking here if the drop glue + // didn’t code in the checks inside itself. + build::Invoke(bcx, + drop_fn, + &[llvalue], + intermediate_bcx.llbb, + unwind.llbb, + None, + DebugLoc::None); + // FIXME: perhaps we also should fill inside failed branch? We do not want to re-drop a + // failed drop again by mistake. (conflicts with MSVC SEH if we don’t want to introduce + // a heap of hacks) + self.drop_fill(intermediate_bcx, lvalue.llval, ty); + build::Br(intermediate_bcx, self.llblock(target), DebugLoc::None); + } else { + build::Call(bcx, drop_fn, &[llvalue], None, DebugLoc::None); + self.drop_fill(bcx, lvalue.llval, ty); + build::Br(bcx, self.llblock(target), DebugLoc::None); + } + } + + pub fn drop_fill(&mut self, bcx: Block<'bcx, 'tcx>, value: ValueRef, ty: Ty<'tcx>) { + let llty = type_of::type_of(bcx.ccx(), ty); + let llptr = build::PointerCast(bcx, value, Type::i8(bcx.ccx()).ptr_to()); + let filling = common::C_u8(bcx.ccx(), adt::DTOR_DONE); + let size = machine::llsize_of(bcx.ccx(), llty); + let align = common::C_u32(bcx.ccx(), machine::llalign_of_min(bcx.ccx(), llty)); + base::call_memset(&build::B(bcx), llptr, filling, size, align, false); + } +} diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index b19ecc45a4e5e..37c6d3975675e 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -196,6 +196,7 @@ mod analyze; mod block; mod constant; mod did; +mod drop; mod lvalue; mod operand; mod rvalue; diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs index 114e78b05bddd..45cbe2e081f19 100644 --- a/src/librustc_trans/trans/mir/operand.rs +++ b/src/librustc_trans/trans/mir/operand.rs @@ -147,22 +147,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - pub fn trans_operand_into(&mut self, - bcx: Block<'bcx, 'tcx>, - lldest: ValueRef, - operand: &mir::Operand<'tcx>) - { - debug!("trans_operand_into(lldest={}, operand={:?})", - bcx.val_to_string(lldest), - operand); - - // FIXME: consider not copying constants through the - // stack. - - let o = self.trans_operand(bcx, operand); - self.store_operand(bcx, lldest, o); - } - pub fn store_operand(&mut self, bcx: Block<'bcx, 'tcx>, lldest: ValueRef, diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index e280eff34c894..a40871c6cd6a1 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -43,11 +43,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { rvalue); match *rvalue { - mir::Rvalue::Use(ref operand) => { - self.trans_operand_into(bcx, dest.llval, operand); - bcx - } - mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => { if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { // into-coerce of a thin pointer to a fat pointer - just @@ -168,6 +163,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match *rvalue { mir::Rvalue::Use(ref operand) => { + // FIXME: consider not copying constants through stack. (fixable by translating + // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) let operand = self.trans_operand(bcx, operand); (bcx, operand) } From 569b18f336e3eaf2748eaf377f12c907fa423f1b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 31 Jan 2016 15:07:18 +0200 Subject: [PATCH 2/3] Add some tests for dynamic dropping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also remove these drop-glue i8 things… They for some reason make these completely non-MIR tests fail after dyndrop commit which has literally 0 changes around the regular old trans. Wut? --- src/test/run-fail/mir_dynamic_drops_1.rs | 41 ++++++++++++++++++++++ src/test/run-fail/mir_dynamic_drops_2.rs | 39 +++++++++++++++++++++ src/test/run-fail/mir_dynamic_drops_3.rs | 43 ++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 src/test/run-fail/mir_dynamic_drops_1.rs create mode 100644 src/test/run-fail/mir_dynamic_drops_2.rs create mode 100644 src/test/run-fail/mir_dynamic_drops_3.rs diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs new file mode 100644 index 0000000000000..f3c2eafde2459 --- /dev/null +++ b/src/test/run-fail/mir_dynamic_drops_1.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(rustc_attrs)] +// error-pattern:drop 1 +// error-pattern:drop 2 +use std::io::{self, Write}; + + +/// Structure which will not allow to be dropped twice. +struct Droppable(bool, u32); +impl Drop for Droppable { + fn drop(&mut self) { + if self.0 { + writeln!(io::stderr(), "{} dropped twice", self.1); + ::std::process::exit(1); + } + writeln!(io::stderr(), "drop {}", self.1); + self.0 = true; + } +} + +#[rustc_mir] +fn mir(){ + let x = Droppable(false, 1); + let y = Droppable(false, 2); + let mut z = x; + let k = y; + z = k; +} + +fn main() { + mir(); + panic!(); +} diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs new file mode 100644 index 0000000000000..ada04dfce6471 --- /dev/null +++ b/src/test/run-fail/mir_dynamic_drops_2.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(rustc_attrs)] +// error-pattern:drop 1 +use std::io::{self, Write}; + + +/// Structure which will not allow to be dropped twice. +struct Droppable(bool, u32); +impl Drop for Droppable { + fn drop(&mut self) { + if self.0 { + writeln!(io::stderr(), "{} dropped twice", self.1); + ::std::process::exit(1); + } + writeln!(io::stderr(), "drop {}", self.1); + self.0 = true; + } +} + +#[rustc_mir] +fn mir(d: Droppable){ + loop { + let x = d; + break; + } +} + +fn main() { + mir(Droppable(false, 1)); + panic!(); +} diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs new file mode 100644 index 0000000000000..cfbfb07595462 --- /dev/null +++ b/src/test/run-fail/mir_dynamic_drops_3.rs @@ -0,0 +1,43 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(rustc_attrs)] +// error-pattern:unwind happens +// error-pattern:drop 3 +// error-pattern:drop 2 +// error-pattern:drop 1 +use std::io::{self, Write}; + + +/// Structure which will not allow to be dropped twice. +struct Droppable(bool, u32); +impl Drop for Droppable { + fn drop(&mut self) { + if self.0 { + writeln!(io::stderr(), "{} dropped twice", self.1); + ::std::process::exit(1); + } + writeln!(io::stderr(), "drop {}", self.1); + self.0 = true; + } +} + +fn may_panic() -> Droppable { + panic!("unwind happens"); +} + +#[rustc_mir] +fn mir(d: Droppable){ + let y = Droppable(false, 2); + let x = [Droppable(false, 1), y, d, may_panic()]; +} + +fn main() { + mir(Droppable(false, 3)); +} From a147703dc169f75aae96824ff3f0636886c86e24 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 6 Feb 2016 15:41:24 +0200 Subject: [PATCH 3/3] [MIR] Implement zero-on-move Also fix the tests to catch the double-drop on move. --- src/librustc_trans/trans/mir/drop.rs | 25 +++++++++++++++++++++++- src/librustc_trans/trans/mir/rvalue.rs | 21 ++++++++++++-------- src/test/run-fail/mir_dynamic_drops_1.rs | 14 +++++++------ src/test/run-fail/mir_dynamic_drops_2.rs | 11 ++++++----- src/test/run-fail/mir_dynamic_drops_3.rs | 19 ++++++++++-------- 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/trans/mir/drop.rs b/src/librustc_trans/trans/mir/drop.rs index 13e9840f7b8b8..256e49d601f03 100644 --- a/src/librustc_trans/trans/mir/drop.rs +++ b/src/librustc_trans/trans/mir/drop.rs @@ -21,7 +21,7 @@ use trans::machine; use trans::type_of; use trans::type_::Type; -use super::MirContext; +use super::{MirContext, TempRef}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_drop(&mut self, @@ -78,4 +78,27 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let align = common::C_u32(bcx.ccx(), machine::llalign_of_min(bcx.ccx(), llty)); base::call_memset(&build::B(bcx), llptr, filling, size, align, false); } + + pub fn set_operand_dropped(&mut self, + bcx: Block<'bcx, 'tcx>, + operand: &mir::Operand<'tcx>) { + match *operand { + mir::Operand::Constant(_) => return, + mir::Operand::Consume(ref lvalue) => { + if let mir::Lvalue::Temp(idx) = *lvalue { + if let TempRef::Operand(..) = self.temps[idx as usize] { + return // we do not handle these, should we? + } + } + let lvalue = self.trans_lvalue(bcx, lvalue); + let ty = lvalue.ty.to_ty(bcx.tcx()); + if !glue::type_needs_drop(bcx.tcx(), ty) || + common::type_is_fat_ptr(bcx.tcx(), ty) { + return + } else { + self.drop_fill(bcx, lvalue.llval, ty); + } + } + } + } } diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index a40871c6cd6a1..23cf4d429b6a4 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -43,6 +43,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { rvalue); match *rvalue { + mir::Rvalue::Use(ref operand) => { + // FIXME: consider not copying constants through stack. (fixable by translating + // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) + let tr_operand = self.trans_operand(bcx, operand); + self.store_operand(bcx, dest.llval, tr_operand); + self.set_operand_dropped(bcx, operand); + bcx + } + mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, cast_ty) => { if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { // into-coerce of a thin pointer to a fat pointer - just @@ -162,13 +171,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { - mir::Rvalue::Use(ref operand) => { - // FIXME: consider not copying constants through stack. (fixable by translating - // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) - let operand = self.trans_operand(bcx, operand); - (bcx, operand) - } - mir::Rvalue::Cast(ref kind, ref operand, cast_ty) => { let operand = self.trans_operand(bcx, operand); debug!("cast operand is {}", operand.repr(bcx)); @@ -398,6 +400,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }) } + mir::Rvalue::Use(..) | mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) | mir::Rvalue::Slice { .. } | @@ -508,7 +511,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool { match *rvalue { - mir::Rvalue::Use(..) | // (*) mir::Rvalue::Ref(..) | mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) @@ -516,6 +518,7 @@ pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool { mir::Rvalue::UnaryOp(..) | mir::Rvalue::Box(..) => true, + mir::Rvalue::Use(..) | // (**) mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) | mir::Rvalue::Slice { .. } | @@ -524,4 +527,6 @@ pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool { } // (*) this is only true if the type is suitable + // (**) we need to zero-out the old value before moving, so we are restricted to either + // ensuring all users of `Use` set it themselves or not allowing to “create” operand for it. } diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs index f3c2eafde2459..07cc066355a4b 100644 --- a/src/test/run-fail/mir_dynamic_drops_1.rs +++ b/src/test/run-fail/mir_dynamic_drops_1.rs @@ -14,22 +14,24 @@ use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. -struct Droppable(bool, u32); -impl Drop for Droppable { +struct Droppable<'a>(&'a mut bool, u32); +impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { - if self.0 { + if *self.0 { writeln!(io::stderr(), "{} dropped twice", self.1); ::std::process::exit(1); } writeln!(io::stderr(), "drop {}", self.1); - self.0 = true; + *self.0 = true; } } #[rustc_mir] fn mir(){ - let x = Droppable(false, 1); - let y = Droppable(false, 2); + let mut b1 = false; + let mut b2 = false; + let x = Droppable(&mut b1, 1); + let y = Droppable(&mut b2, 2); let mut z = x; let k = y; z = k; diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs index ada04dfce6471..655991f944c14 100644 --- a/src/test/run-fail/mir_dynamic_drops_2.rs +++ b/src/test/run-fail/mir_dynamic_drops_2.rs @@ -13,15 +13,15 @@ use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. -struct Droppable(bool, u32); -impl Drop for Droppable { +struct Droppable<'a>(&'a mut bool, u32); +impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { - if self.0 { + if *self.0 { writeln!(io::stderr(), "{} dropped twice", self.1); ::std::process::exit(1); } writeln!(io::stderr(), "drop {}", self.1); - self.0 = true; + *self.0 = true; } } @@ -34,6 +34,7 @@ fn mir(d: Droppable){ } fn main() { - mir(Droppable(false, 1)); + let mut d1 = false; + mir(Droppable(&mut d1, 1)); panic!(); } diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs index cfbfb07595462..058f3decbfdb6 100644 --- a/src/test/run-fail/mir_dynamic_drops_3.rs +++ b/src/test/run-fail/mir_dynamic_drops_3.rs @@ -16,28 +16,31 @@ use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. -struct Droppable(bool, u32); -impl Drop for Droppable { +struct Droppable<'a>(&'a mut bool, u32); +impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { - if self.0 { + if *self.0 { writeln!(io::stderr(), "{} dropped twice", self.1); ::std::process::exit(1); } writeln!(io::stderr(), "drop {}", self.1); - self.0 = true; + *self.0 = true; } } -fn may_panic() -> Droppable { +fn may_panic<'a>() -> Droppable<'a> { panic!("unwind happens"); } #[rustc_mir] fn mir(d: Droppable){ - let y = Droppable(false, 2); - let x = [Droppable(false, 1), y, d, may_panic()]; + let mut d1 = false; + let mut d2 = false; + let y = Droppable(&mut d2, 2); + let x = [Droppable(&mut d1, 1), y, d, may_panic()]; } fn main() { - mir(Droppable(false, 3)); + let mut d3 = false; + mir(Droppable(&mut d3, 3)); }