Skip to content

Commit

Permalink
create a drop ladder for an array if any value is moved out
Browse files Browse the repository at this point in the history
  • Loading branch information
mikhail-m1 committed Dec 2, 2017
1 parent 8bcbf91 commit 7be2fd8
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 9 deletions.
7 changes: 6 additions & 1 deletion src/librustc_mir/dataflow/drop_flag_effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx,
place: &mir::Place<'tcx>) -> bool {
let ty = place.ty(mir, tcx).to_ty(tcx);
match ty.sty {
ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
ty::TyArray(..) => {
debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
place, ty);
false
}
ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
place, ty);
true
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
Some(())
}
fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
None
}
}

/// Build a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
Expand Down
14 changes: 14 additions & 0 deletions src/librustc_mir/transform/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,20 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
})
}

fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
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 deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
match p {
Expand Down
34 changes: 27 additions & 7 deletions src/librustc_mir/util/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc::ty::util::IntTypeExt;
use rustc_data_structures::indexed_vec::Idx;
use util::patch::MirPatch;

use std::iter;
use std::{iter, u32};

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum DropFlagState {
Expand Down Expand Up @@ -95,6 +95,7 @@ pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug {
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path>;
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path>;
fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option<Self::Path>;
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path>;
}

#[derive(Debug)]
Expand Down Expand Up @@ -632,18 +633,36 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
loop_block
}

fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
debug!("open_drop_for_array({:?})", ety);
fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock {
debug!("open_drop_for_array({:?}, {:?})", ety, opt_size);

// if size_of::<ety>() == 0 {
// index_based_loop
// } else {
// ptr_based_loop
// }

let tcx = self.tcx();
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<D::Path>)> = (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 (succ, unwind) = self.drop_ladder_bottom();
return self.drop_ladder(fields, succ, unwind).0
}
}

let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
let tcx = self.tcx();
let size = &Place::Local(self.new_temp(tcx.types.usize));
let size_is_zero = &Place::Local(self.new_temp(tcx.types.bool));
let base_block = BasicBlockData {
Expand Down Expand Up @@ -779,9 +798,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
let succ = self.succ;
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
}
ty::TyArray(ety, _) | ty::TySlice(ety) => {
self.open_drop_for_array(ety)
}
ty::TyArray(ety, size) => self.open_drop_for_array(
ety, size.val.to_const_int().and_then(|v| v.to_u64())),
ty::TySlice(ety) => self.open_drop_for_array(ety, None),

_ => bug!("open drop from non-ADT `{:?}`", ty)
}
}
Expand Down
38 changes: 37 additions & 1 deletion src/test/run-pass/dynamic-drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// ignore-wasm32-bare compiled with panic=abort by default

#![feature(generators, generator_trait, untagged_unions)]
#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)]

use std::cell::{Cell, RefCell};
use std::ops::Generator;
Expand Down Expand Up @@ -195,6 +195,33 @@ fn vec_unreachable(a: &Allocator) {
let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
}

fn slice_pattern_first(a: &Allocator) {
let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_middle(a: &Allocator) {
let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_two(a: &Allocator) {
let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_last(a: &Allocator) {
let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_one_of(a: &Allocator, i: usize) {
let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
let _x = match i {
0 => { let [a, ..] = array; a }
1 => { let [_, a, ..] = array; a }
2 => { let [_, _, a, _] = array; a }
3 => { let [_, _, _, a] = array; a }
_ => panic!("unmatched"),
};
}

fn run_test<F>(mut f: F)
where F: FnMut(&Allocator)
{
Expand Down Expand Up @@ -264,5 +291,14 @@ fn main() {

run_test(|a| mixed_drop_and_nondrop(a));

run_test(|a| slice_pattern_first(a));
run_test(|a| slice_pattern_middle(a));
run_test(|a| slice_pattern_two(a));
run_test(|a| slice_pattern_last(a));
run_test(|a| slice_pattern_one_of(a, 0));
run_test(|a| slice_pattern_one_of(a, 1));
run_test(|a| slice_pattern_one_of(a, 2));
run_test(|a| slice_pattern_one_of(a, 3));

run_test_nopanic(|a| union1(a));
}

0 comments on commit 7be2fd8

Please sign in to comment.