diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 2713a3c371d..bd38f554dc9 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -12,7 +12,6 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; -use rustc::util::common::ErrorReported; use rustc_data_structures::indexed_vec::{IndexVec}; use syntax::codemap::DUMMY_SP; @@ -198,6 +197,11 @@ struct MoveDataBuilder<'a, 'tcx: 'a> { data: MoveData<'tcx>, } +pub enum MovePathError { + IllegalMove, + UnionMove { path: MovePathIndex }, +} + impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -256,7 +260,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { move_path } - /// This creates a MovePath for a given lvalue, returning an `ErrorReported` + /// This creates a MovePath for a given lvalue, returning an `MovePathError` /// if that lvalue can't be moved from. /// /// NOTE: lvalues behind references *do not* get a move path, which is @@ -264,7 +268,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { /// /// Maybe we should have seperate "borrowck" and "moveck" modes. fn move_path_for(&mut self, lval: &Lvalue<'tcx>) - -> Result + -> Result { debug!("lookup({:?})", lval); match *lval { @@ -272,7 +276,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), // error: can't move out of a static - Lvalue::Static(..) => Err(ErrorReported), + Lvalue::Static(..) => Err(MovePathError::IllegalMove), Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { Some(ptr) => Ok(ptr), ref mut ptr @ None => { @@ -300,21 +304,28 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn move_path_for_projection(&mut self, lval: &Lvalue<'tcx>, proj: &LvalueProjection<'tcx>) - -> Result + -> Result { let base = try!(self.move_path_for(&proj.base)); let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); match lv_ty.sty { // error: can't move out of borrowed content - ty::TyRef(..) | ty::TyRawPtr(..) => return Err(ErrorReported), + ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), // error: can't move out of struct with destructor - ty::TyStruct(adt, _) | ty::TyEnum(adt, _) if adt.has_dtor() => - return Err(ErrorReported), - - ty::TyArray(..) | ty::TySlice(..) => match proj.elem { + ty::TyAdt(adt, _) if adt.has_dtor() => + return Err(MovePathError::IllegalMove), + // move out of union - always move the entire union + ty::TyAdt(adt, _) if adt.is_union() => + return Err(MovePathError::UnionMove { path: base }), + // error: can't move out of a slice + ty::TySlice(..) => + return Err(MovePathError::IllegalMove), + ty::TyArray(..) => match proj.elem { // error: can't move out of an array - ProjectionElem::Index(..) => return Err(ErrorReported), - _ => {} + ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove), + _ => { + // FIXME: still badly broken + } }, _ => {} }; @@ -521,13 +532,16 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { return } - let path = self.move_path_for(lval).unwrap_or_else(|_| { - // Moving out of a bad path. Eventually, this should be a MIR - // borrowck error instead of a bug. - span_bug!(self.mir.span, - "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", - lval, lv_ty, loc); - }); + let path = match self.move_path_for(lval) { + Ok(path) | Err(MovePathError::UnionMove { path }) => path, + Err(MovePathError::IllegalMove) => { + // Moving out of a bad path. Eventually, this should be a MIR + // borrowck error instead of a bug. + span_bug!(self.mir.span, + "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", + lval, lv_ty, loc); + } + }; let move_out = self.data.moves.push(MoveOut { path: path, source: loc }); debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 7c2410a2c14..5b5d782bc83 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -256,12 +256,12 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx let ty = lv.ty(mir, tcx).to_ty(tcx); match ty.sty { ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { - debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false", + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => true", lv, ty); true } - ty::TyAdt(def, _) if def.has_dtor() => { - debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", + ty::TyAdt(def, _) if def.has_dtor() || def.is_union() => { + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true", lv, ty); true } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 2b016dfb33e..a2cca206409 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] +#![feature(untagged_unions)] use std::cell::{Cell, RefCell}; use std::panic; @@ -111,6 +111,20 @@ fn assignment1(a: &Allocator, c0: bool) { _v = _w; } +#[allow(unions_with_drop_fields)] +union Boxy { + a: T, + b: T, +} + +fn union1(a: &Allocator) { + unsafe { + let mut u = Boxy { a: a.alloc() }; + u.b = a.alloc(); + drop(u.a); + } +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -136,6 +150,13 @@ fn run_test(mut f: F) } } +fn run_test_nopanic(mut f: F) + where F: FnMut(&Allocator) +{ + let first_alloc = Allocator::new(usize::MAX); + f(&first_alloc); +} + fn main() { run_test(|a| dynamic_init(a, false)); run_test(|a| dynamic_init(a, true)); @@ -149,4 +170,6 @@ fn main() { run_test(|a| assignment1(a, false)); run_test(|a| assignment1(a, true)); + + run_test_nopanic(|a| union1(a)); }