Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create a drop ladder for an array if any value is moved out #46334

Merged
merged 1 commit into from
Dec 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tried compile

let b : [bool; 5_000_000_000] = [true; 5000000000];
let [x,..] = b;

but compiler fails on earlier stage with OOM

"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));
}