diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 46193dedf8968..59eeb81a07638 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -268,7 +268,11 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { None } - fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) { + fn clear_drop_flag(&mut self, + _location: Location, + _path: Self::Path, + _mode: DropFlagMode, + _opt_flag: Option) { } fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option { @@ -280,8 +284,9 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option { Some(()) } - fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option { - None + fn array_subpaths(&self, _path: Self::Path, _size: u64) + -> Vec<(Place<'tcx>, Option, Option)> { + vec![] } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index b075d2637da9b..26fc4f79aa2fc 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -29,7 +29,7 @@ use util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode}; use syntax::ast; use syntax_pos::Span; -use std::fmt; +use std::{fmt, u32}; pub struct ElaborateDrops; @@ -74,6 +74,7 @@ impl MirPass for ElaborateDrops { flow_inits, flow_uninits, drop_flags: FxHashMap(), + array_items_drop_flags: FxHashMap(), patch: MirPatch::new(mir), }.elaborate() }; @@ -224,6 +225,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { ((some_live, some_dead), children_count != 1) } }; + match (maybe_live, maybe_dead, multipart) { (false, _, _) => DropStyle::Dead, (true, false, _) => DropStyle::Static, @@ -232,7 +234,16 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } } - fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) { + fn clear_drop_flag( + &mut self, + loc: Location, + path: Self::Path, + mode: DropFlagMode, + opt_flag: Option) { + if let Some(flag) = opt_flag { + self.ctxt.set_drop_flag_impl(loc, flag, DropFlagState::Absent); + return; + } match mode { DropFlagMode::Shallow => { self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent); @@ -257,18 +268,38 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { }) } - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, .. - } => offset == index, - &Projection { - elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, .. - } => size - offset == index, - _ => false - } - }) + fn array_subpaths(&self, path: Self::Path, size: u64) + -> Vec<(Place<'tcx>, Option, Option)> { + if dataflow::move_path_children_matching(self.ctxt.move_data(), path, + |_| true).is_none() { + return vec![]; + } + + assert!(size <= (u32::MAX as u64), + "move out check doesn't implemented for array bigger then u32"); + + let size = size as u32; + let flags = self.ctxt.array_items_drop_flags.get(&path); + (0..size).map(|i| { + let move_path = dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| + match p.elem { + ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false} => + offset == i, + ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => + size - offset == i, + ProjectionElem::Subslice{from, to} => from <= i && i < size - to, + _ => false + } + ); + let place = &self.ctxt.move_data().move_paths[path].place; + (place.clone().elem(ProjectionElem::ConstantIndex{ + offset: i, + min_length: size, + from_end: false + }), + move_path, + move_path.and(flags.map(|f| f[i as usize]))) + }).collect() } fn deref_subpath(&self, path: Self::Path) -> Option { @@ -292,17 +323,27 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } fn get_drop_flag(&mut self, path: Self::Path) -> Option> { - self.ctxt.drop_flag(path).map(Operand::Copy) + self.ctxt.drop_flag(path).map(|f| match f{ + DropFlag::Single(l) => Operand::Copy(Place::Local(*l)), + DropFlag::Subslice(_) => + panic!("get_drop_flag shouldn't be calles for sublice move path") + }) } } +enum DropFlag { + Single(Local), + Subslice(Vec), +} + struct ElaborateDropsCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, env: &'a MoveDataParamEnv<'tcx, 'tcx>, flow_inits: DataflowResults>, flow_uninits: DataflowResults>, - drop_flags: FxHashMap, + drop_flags: FxHashMap, + array_items_drop_flags: FxHashMap>, patch: MirPatch<'tcx>, } @@ -329,15 +370,77 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; + + match self.move_data().move_paths[index].place { + Place::Projection(box Projection{ref base, + elem: ProjectionElem::Subslice{from, to}}) => { + let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + if let ty::TyArray(_, n) = base_ty.sty { + let n = n.val.to_const_int().and_then(|v| v.to_u64()) + .expect("expected u64 size") as usize; + let from = from as usize; + let to = to as usize; + let flags = self.drop_flags_for_array(n, index)[from .. n-to] + .iter() + .map(|x| *x).collect(); + let span = self.mir.span; + self.drop_flags.entry(index).or_insert_with(|| { + debug!("create_drop_flags for subslice({:?}, {:?}, {:?})", + index, span, flags); + DropFlag::Subslice(flags) + }); + return; + } + } + Place::Projection(box Projection{ref base, + elem: ProjectionElem::ConstantIndex{offset, + min_length: _, + from_end}}) => { + let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + if let ty::TyArray(_, n) = base_ty.sty { + let n = n.val.to_const_int().and_then(|v| v.to_u64()) + .expect("expected u64 size") as usize; + let offset = offset as usize; + let offset = if from_end { n-offset } else { offset }; + let flag = self.drop_flags_for_array(n, index)[offset]; + + let span = self.mir.span; + self.drop_flags.entry(index).or_insert_with(|| { + debug!("create_drop_flags for const index({:?}, {:?}, {:?})", + (offset, from_end), span, flag); + DropFlag::Single(flag) + }); + return; + } + } + _ => {} + } + let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { - patch.new_internal(tcx.types.bool, span) + DropFlag::Single(patch.new_internal(tcx.types.bool, span)) }); } - fn drop_flag(&mut self, index: MovePathIndex) -> Option> { - self.drop_flags.get(&index).map(|t| Place::Local(*t)) + fn drop_flags_for_array(&mut self, n: usize, index: MovePathIndex) -> &Vec { + let tcx = self.tcx; + let span = self.mir.span; + let parent_index = self.move_data().move_paths[index].parent + .expect("subslice has parent"); + let patch = &mut self.patch; + self.array_items_drop_flags.entry(parent_index) + .or_insert_with(|| { + let flags = (0..n).map(|_| patch.new_internal(tcx.types.bool, span)) + .collect(); + debug!("create_drop_flags for array with subslice({:?}, {:?}, {:?})", + parent_index, span, flags); + flags + }) + } + + fn drop_flag(&mut self, index: MovePathIndex) -> Option<&DropFlag> { + self.drop_flags.get(&index) } /// create a patch that elaborates all drops in the input @@ -389,6 +492,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } }; + on_all_drop_children_bits(self.tcx, self.mir, self.env, path, |child| { let (maybe_live, maybe_dead) = init_data.state(child); debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", @@ -548,11 +652,20 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { }))) } + fn set_drop_flag_impl(&mut self, loc: Location, flag: Local, val: DropFlagState) { + let span = self.patch.source_info_for_location(self.mir, loc).span; + let val = self.constant_bool(span, val.value()); + self.patch.add_assign(loc, Place::Local(flag), val); + } + fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { - if let Some(&flag) = self.drop_flags.get(&path) { - let span = self.patch.source_info_for_location(self.mir, loc).span; - let val = self.constant_bool(span, val.value()); - self.patch.add_assign(loc, Place::Local(flag), val); + match self.drop_flags.get(&path) { + Some(DropFlag::Single(flag)) => self.set_drop_flag_impl(loc, *flag, val), + Some(DropFlag::Subslice(flags)) => + for flag in flags { + self.set_drop_flag_impl(loc, *flag, val); + } + _ => {} } } @@ -561,7 +674,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { - self.patch.add_assign(loc, Place::Local(*flag), false_.clone()); + match flag { + DropFlag::Single(flag) => + self.patch.add_assign(loc, Place::Local(*flag), false_.clone()), + DropFlag::Subslice(flags) => + for flag in flags { + self.patch.add_assign(loc, Place::Local(*flag), false_.clone()); + }, + } } } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 3331bc9e59e0b..c9d0b560f0e0d 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -19,7 +19,7 @@ use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; -use std::{iter, u32}; +use std::iter; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { @@ -89,13 +89,17 @@ pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug { fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; fn get_drop_flag(&mut self, path: Self::Path) -> Option>; - fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode); - + fn clear_drop_flag(&mut self, + location: Location, + path: Self::Path, + mode: DropFlagMode, + opt_drop_flag: Option); fn field_subpath(&self, path: Self::Path, field: Field) -> Option; fn deref_subpath(&self, path: Self::Path) -> Option; fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option; - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option; + fn array_subpaths(&self, path: Self::Path, size: u64) + -> Vec<(Place<'tcx>, Option, Option)>; } #[derive(Debug)] @@ -124,7 +128,7 @@ pub fn elaborate_drop<'b, 'tcx, D>( { DropCtxt { elaborator, source_info, place, path, succ, unwind - }.elaborate_drop(bb) + }.elaborate_drop(bb, None) } impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> @@ -156,7 +160,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// /// FIXME: I think we should just control the flags externally /// and then we do not need this machinery. - pub fn elaborate_drop<'a>(&mut self, bb: BasicBlock) { + pub fn elaborate_drop<'a>(&mut self, bb: BasicBlock, opt_flag: Option) { debug!("elaborate_drop({:?})", self); let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep); debug!("elaborate_drop({:?}): live - {:?}", self, style); @@ -168,7 +172,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> } DropStyle::Static => { let loc = self.terminator_loc(bb); - self.elaborator.clear_drop_flag(loc, self.path, DropFlagMode::Deep); + self.elaborator.clear_drop_flag(loc, self.path, DropFlagMode::Deep, None); self.elaborator.patch().patch_terminator(bb, TerminatorKind::Drop { location: self.place.clone(), target: self.succ, @@ -178,7 +182,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> DropStyle::Conditional => { let unwind = self.unwind; // FIXME(#6393) let succ = self.succ; - let drop_bb = self.complete_drop(Some(DropFlagMode::Deep), succ, unwind); + let drop_bb = self.complete_drop(Some(DropFlagMode::Deep), succ, unwind, opt_flag); self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto { target: drop_bb }); @@ -199,7 +203,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> variant_path: D::Path, variant: &'tcx ty::VariantDef, substs: &'tcx Substs<'tcx>) - -> Vec<(Place<'tcx>, Option)> + -> Vec<(Place<'tcx>, Option, Option)> { variant.fields.iter().enumerate().map(|(i, f)| { let field = Field::new(i); @@ -210,7 +214,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> &f.ty(self.tcx(), substs), self.elaborator.param_env() ); - (base_place.clone().field(field, field_ty), subpath) + (base_place.clone().field(field, field_ty), subpath, None) }).collect() } @@ -218,7 +222,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> place: &Place<'tcx>, path: Option, succ: BasicBlock, - unwind: Unwind) + unwind: Unwind, + opt_flag: Option) -> BasicBlock { if let Some(path) = path { @@ -228,7 +233,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> elaborator: self.elaborator, source_info: self.source_info, path, place, succ, unwind, - }.elaborated_drop_block() + }.elaborated_drop_block(opt_flag) } else { debug!("drop_subpath: for rest field {:?}", place); @@ -239,7 +244,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // Using `self.path` here to condition the drop on // our own drop flag. path: self.path - }.complete_drop(None, succ, unwind) + }.complete_drop(None, succ, unwind, opt_flag) } } @@ -252,13 +257,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn drop_halfladder(&mut self, unwind_ladder: &[Unwind], mut succ: BasicBlock, - fields: &[(Place<'tcx>, Option)]) + fields: &[(Place<'tcx>, Option, Option)]) -> Vec { Some(succ).into_iter().chain( fields.iter().rev().zip(unwind_ladder) - .map(|(&(ref place, path), &unwind_succ)| { - succ = self.drop_subpath(place, path, succ, unwind_succ); + .map(|(&(ref place, path, opt_flag), &unwind_succ)| { + succ = self.drop_subpath(place, path, succ, unwind_succ, opt_flag); succ }) ).collect() @@ -270,9 +275,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // which is invalidated after the ADT is dropped. let (succ, unwind) = (self.succ, self.unwind); // FIXME(#6393) ( - self.drop_flag_reset_block(DropFlagMode::Shallow, succ, unwind), + self.drop_flag_reset_block(DropFlagMode::Shallow, succ, unwind, None), unwind.map(|unwind| { - self.drop_flag_reset_block(DropFlagMode::Shallow, unwind, Unwind::InCleanup) + self.drop_flag_reset_block(DropFlagMode::Shallow, unwind, Unwind::InCleanup, None) }) ) } @@ -295,7 +300,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// NOTE: this does not clear the master drop flag, so you need /// to point succ/unwind on a `drop_ladder_bottom`. fn drop_ladder<'a>(&mut self, - fields: Vec<(Place<'tcx>, Option)>, + fields: Vec<(Place<'tcx>, Option, Option)>, succ: BasicBlock, unwind: Unwind) -> (BasicBlock, Unwind) @@ -303,7 +308,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> debug!("drop_ladder({:?}, {:?})", self, fields); let mut fields = fields; - fields.retain(|&(ref place, _)| { + fields.retain(|&(ref place, ..)| { self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env()) }); @@ -330,7 +335,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let fields = tys.iter().enumerate().map(|(i, &ty)| { (self.place.clone().field(Field::new(i), ty), - self.elaborator.field_subpath(self.path, Field::new(i))) + self.elaborator.field_subpath(self.path, Field::new(i)), + None) }).collect(); let (succ, unwind) = self.drop_ladder_bottom(); @@ -351,7 +357,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.box_free_block(ty, unwind, Unwind::InCleanup) }); - self.drop_subpath(&interior, interior_path, succ, unwind_succ) + self.drop_subpath(&interior, interior_path, succ, unwind_succ, None) } fn open_drop_for_adt<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) @@ -508,7 +514,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> is_cleanup: unwind.is_cleanup(), }; let switch_block = self.elaborator.patch().new_block(switch_block); - self.drop_flag_test_block(switch_block, succ, unwind) + self.drop_flag_test_block(switch_block, succ, unwind, None) } fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Unwind)) @@ -636,31 +642,20 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option) -> BasicBlock { debug!("open_drop_for_array({:?}, {:?})", ety, opt_size); - // if size_of::() == 0 { - // index_based_loop - // } else { - // ptr_based_loop - // } - + // if any value has been moved out, creates the ladder like for tuples if let Some(size) = opt_size { - assert!(size <= (u32::MAX as u64), - "move out check doesn't implemented for array bigger then u32"); - let size = size as u32; - let fields: Vec<(Place<'tcx>, Option)> = (0..size).map(|i| { - (self.place.clone().elem(ProjectionElem::ConstantIndex{ - offset: i, - min_length: size, - from_end: false - }), - self.elaborator.array_subpath(self.path, i, size)) - }).collect(); - - if fields.iter().any(|(_,path)| path.is_some()) { + let fields = self.elaborator.array_subpaths(self.path, size); + if !fields.is_empty() { let (succ, unwind) = self.drop_ladder_bottom(); return self.drop_ladder(fields, succ, unwind).0 } } + // if size_of::() == 0 { + // index_based_loop + // } else { + // ptr_based_loop + // } let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); let tcx = self.tcx(); let size = &Place::Local(self.new_temp(tcx.types.usize)); @@ -758,8 +753,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }); // FIXME(#34708): handle partially-dropped array/slice elements. - let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); - self.drop_flag_test_block(reset_block, succ, unwind) + let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind, None); + self.drop_flag_test_block(reset_block, succ, unwind, None) } /// The slow-path - create an "open", elaborated drop for a type @@ -796,7 +791,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty::TyDynamic(..) => { let unwind = self.unwind; // FIXME(#6393) let succ = self.succ; - self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) + self.complete_drop(Some(DropFlagMode::Deep), succ, unwind, None) } ty::TyArray(ety, size) => self.open_drop_for_array( ety, size.val.to_const_int().and_then(|v| v.to_u64())), @@ -816,39 +811,41 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn complete_drop<'a>(&mut self, drop_mode: Option, succ: BasicBlock, - unwind: Unwind) -> BasicBlock + unwind: Unwind, + opt_flag: Option) -> BasicBlock { debug!("complete_drop({:?},{:?})", self, drop_mode); let drop_block = self.drop_block(succ, unwind); let drop_block = if let Some(mode) = drop_mode { - self.drop_flag_reset_block(mode, drop_block, unwind) + self.drop_flag_reset_block(mode, drop_block, unwind, opt_flag) } else { drop_block }; - self.drop_flag_test_block(drop_block, succ, unwind) + self.drop_flag_test_block(drop_block, succ, unwind, opt_flag) } fn drop_flag_reset_block(&mut self, mode: DropFlagMode, succ: BasicBlock, - unwind: Unwind) -> BasicBlock + unwind: Unwind, + opt_flag: Option) -> BasicBlock { debug!("drop_flag_reset_block({:?},{:?})", self, mode); let block = self.new_block(unwind, TerminatorKind::Goto { target: succ }); let block_start = Location { block: block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, mode); + self.elaborator.clear_drop_flag(block_start, self.path, mode, opt_flag); block } - fn elaborated_drop_block<'a>(&mut self) -> BasicBlock { + fn elaborated_drop_block<'a>(&mut self, opt_flag: Option) -> BasicBlock { debug!("elaborated_drop_block({:?})", self); let unwind = self.unwind; // FIXME(#6393) let succ = self.succ; let blk = self.drop_block(succ, unwind); - self.elaborate_drop(blk); + self.elaborate_drop(blk, opt_flag); blk } @@ -859,7 +856,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> unwind: Unwind, ) -> BasicBlock { let block = self.unelaborated_free_block(ty, target, unwind); - self.drop_flag_test_block(block, target, unwind) + self.drop_flag_test_block(block, target, unwind, None) } fn unelaborated_free_block<'a>( @@ -882,7 +879,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let free_block = self.new_block(unwind, call); let block_start = Location { block: free_block, statement_index: 0 }; - self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow); + self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow, None); free_block } @@ -898,18 +895,22 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn drop_flag_test_block(&mut self, on_set: BasicBlock, on_unset: BasicBlock, - unwind: Unwind) + unwind: Unwind, + opt_flag: Option) -> BasicBlock { let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); - debug!("drop_flag_test_block({:?},{:?},{:?},{:?}) - {:?}", - self, on_set, on_unset, unwind, style); + debug!("drop_flag_test_block({:?},{:?},{:?},{:?}) - {:?} flag {:?}", + self, on_set, on_unset, unwind, style, opt_flag); match style { DropStyle::Dead => on_unset, DropStyle::Static => on_set, DropStyle::Conditional | DropStyle::Open => { - let flag = self.elaborator.get_drop_flag(self.path).unwrap(); + let flag = opt_flag + .map(|l| Operand::Copy(Place::Local(l))) + .or_else(|| self.elaborator.get_drop_flag(self.path)) + .unwrap(); let term = TerminatorKind::if_(self.tcx(), flag, on_set, on_unset); self.new_block(unwind, term) } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 09318e7256fd7..46140c665e3f9 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -222,6 +222,50 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { }; } +fn subslice_pattern_begin(a: &Allocator) { + let[_x.., _] = [a.alloc(), a.alloc(), a.alloc()]; +} + +fn subslice_pattern_end(a: &Allocator) { + let[_x.., _] = [a.alloc(), a.alloc(), a.alloc()]; +} + +fn subslice_pattern_middle(a: &Allocator) { + let[_, _x.., _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()]; +} + +fn subslice_pattern_by_arg(a: &Allocator, arg: bool) { + let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + if arg { + let[_x.., _] = a; + } else { + let[_, _y..] = a; + } +} + +fn subslice_pattern_penultimate_by_arg(a: &Allocator, arg: bool) { + let a = [a.alloc(), a.alloc(), a.alloc()]; + if arg { + let[.., _x, _] = a; + } else { + let[_, _y..] = a; + } +} + +fn subslice_pattern_test_with_drop(a: &Allocator, arg: bool, arg2: bool) { + let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + if arg2 { + drop(a); + return; + } + + if arg { + let[.., _x, _] = a; + } else { + let[_, _y..] = a; + } +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -300,5 +344,20 @@ fn main() { run_test(|a| slice_pattern_one_of(a, 2)); run_test(|a| slice_pattern_one_of(a, 3)); + run_test(|a| subslice_pattern_begin(a)); + run_test(|a| subslice_pattern_end(a)); + run_test(|a| subslice_pattern_middle(a)); + run_test(|a| subslice_pattern_by_arg(a, true)); + run_test(|a| subslice_pattern_by_arg(a, false)); + + run_test(|a| subslice_pattern_penultimate_by_arg(a, true)); + run_test(|a| subslice_pattern_penultimate_by_arg(a, false)); + + + run_test(|a| subslice_pattern_test_with_drop(a, false, false)); + run_test(|a| subslice_pattern_test_with_drop(a, false, true)); + run_test(|a| subslice_pattern_test_with_drop(a, true, false)); + run_test(|a| subslice_pattern_test_with_drop(a, true, true)); + run_test_nopanic(|a| union1(a)); }