Skip to content

Commit 0d11e51

Browse files
committed
Auto merge of #46334 - mikhail-m1:slice_pattern_array_drop, r=arielb1
create a drop ladder for an array if any value is moved out r? @arielb1 first commit for fix #34708 (note: this still handles the subslice case in a very broken manner)
2 parents 9da2112 + 7be2fd8 commit 0d11e51

File tree

5 files changed

+87
-9
lines changed

5 files changed

+87
-9
lines changed

src/librustc_mir/dataflow/drop_flag_effects.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx,
6161
place: &mir::Place<'tcx>) -> bool {
6262
let ty = place.ty(mir, tcx).to_ty(tcx);
6363
match ty.sty {
64-
ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
64+
ty::TyArray(..) => {
65+
debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
66+
place, ty);
67+
false
68+
}
69+
ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
6570
debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
6671
place, ty);
6772
true

src/librustc_mir/shim.rs

+3
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
280280
fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
281281
Some(())
282282
}
283+
fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
284+
None
285+
}
283286
}
284287

285288
/// Build a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.

src/librustc_mir/transform/elaborate_drops.rs

+14
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,20 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
257257
})
258258
}
259259

260+
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
261+
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
262+
match p {
263+
&Projection {
264+
elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
265+
} => offset == index,
266+
&Projection {
267+
elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
268+
} => size - offset == index,
269+
_ => false
270+
}
271+
})
272+
}
273+
260274
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
261275
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
262276
match p {

src/librustc_mir/util/elaborate_drops.rs

+27-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc::ty::util::IntTypeExt;
1919
use rustc_data_structures::indexed_vec::Idx;
2020
use util::patch::MirPatch;
2121

22-
use std::iter;
22+
use std::{iter, u32};
2323

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

100101
#[derive(Debug)]
@@ -632,18 +633,36 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
632633
loop_block
633634
}
634635

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

638639
// if size_of::<ety>() == 0 {
639640
// index_based_loop
640641
// } else {
641642
// ptr_based_loop
642643
// }
643644

644-
let tcx = self.tcx();
645+
if let Some(size) = opt_size {
646+
assert!(size <= (u32::MAX as u64),
647+
"move out check doesn't implemented for array bigger then u32");
648+
let size = size as u32;
649+
let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size).map(|i| {
650+
(self.place.clone().elem(ProjectionElem::ConstantIndex{
651+
offset: i,
652+
min_length: size,
653+
from_end: false
654+
}),
655+
self.elaborator.array_subpath(self.path, i, size))
656+
}).collect();
657+
658+
if fields.iter().any(|(_,path)| path.is_some()) {
659+
let (succ, unwind) = self.drop_ladder_bottom();
660+
return self.drop_ladder(fields, succ, unwind).0
661+
}
662+
}
645663

646664
let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
665+
let tcx = self.tcx();
647666
let size = &Place::Local(self.new_temp(tcx.types.usize));
648667
let size_is_zero = &Place::Local(self.new_temp(tcx.types.bool));
649668
let base_block = BasicBlockData {
@@ -779,9 +798,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
779798
let succ = self.succ;
780799
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
781800
}
782-
ty::TyArray(ety, _) | ty::TySlice(ety) => {
783-
self.open_drop_for_array(ety)
784-
}
801+
ty::TyArray(ety, size) => self.open_drop_for_array(
802+
ety, size.val.to_const_int().and_then(|v| v.to_u64())),
803+
ty::TySlice(ety) => self.open_drop_for_array(ety, None),
804+
785805
_ => bug!("open drop from non-ADT `{:?}`", ty)
786806
}
787807
}

src/test/run-pass/dynamic-drop.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

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

13-
#![feature(generators, generator_trait, untagged_unions)]
13+
#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)]
1414

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

198+
fn slice_pattern_first(a: &Allocator) {
199+
let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
200+
}
201+
202+
fn slice_pattern_middle(a: &Allocator) {
203+
let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
204+
}
205+
206+
fn slice_pattern_two(a: &Allocator) {
207+
let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
208+
}
209+
210+
fn slice_pattern_last(a: &Allocator) {
211+
let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
212+
}
213+
214+
fn slice_pattern_one_of(a: &Allocator, i: usize) {
215+
let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
216+
let _x = match i {
217+
0 => { let [a, ..] = array; a }
218+
1 => { let [_, a, ..] = array; a }
219+
2 => { let [_, _, a, _] = array; a }
220+
3 => { let [_, _, _, a] = array; a }
221+
_ => panic!("unmatched"),
222+
};
223+
}
224+
198225
fn run_test<F>(mut f: F)
199226
where F: FnMut(&Allocator)
200227
{
@@ -264,5 +291,14 @@ fn main() {
264291

265292
run_test(|a| mixed_drop_and_nondrop(a));
266293

294+
run_test(|a| slice_pattern_first(a));
295+
run_test(|a| slice_pattern_middle(a));
296+
run_test(|a| slice_pattern_two(a));
297+
run_test(|a| slice_pattern_last(a));
298+
run_test(|a| slice_pattern_one_of(a, 0));
299+
run_test(|a| slice_pattern_one_of(a, 1));
300+
run_test(|a| slice_pattern_one_of(a, 2));
301+
run_test(|a| slice_pattern_one_of(a, 3));
302+
267303
run_test_nopanic(|a| union1(a));
268304
}

0 commit comments

Comments
 (0)