create a drop ladder for an array if any value is moved out
This commit is contained in:
parent
8bcbf91a86
commit
7be2fd853a
5 changed files with 87 additions and 9 deletions
|
@ -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
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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)]
|
||||
|
@ -632,8 +633,8 @@ 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
|
||||
|
@ -641,9 +642,27 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
// 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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue