Skip to content

Commit a5a690c

Browse files
committed
Auto merge of rust-lang#109008 - clubby789:drop-elaborate-array, r=davidtwco
Drop array patterns using subslices Fixes rust-lang#109004 Drops contiguous subslices of an array when moving elements out with a pattern, which improves perf for large arrays r? `@compiler-errors`
2 parents 11cd4ff + ce2d528 commit a5a690c

File tree

2 files changed

+70
-18
lines changed

2 files changed

+70
-18
lines changed

compiler/rustc_mir_dataflow/src/elaborate_drops.rs

+54-18
Original file line numberDiff line numberDiff line change
@@ -729,23 +729,59 @@ where
729729
let tcx = self.tcx();
730730

731731
if let Some(size) = opt_size {
732-
let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size)
733-
.map(|i| {
734-
(
735-
tcx.mk_place_elem(
736-
self.place,
737-
ProjectionElem::ConstantIndex {
738-
offset: i,
739-
min_length: size,
740-
from_end: false,
741-
},
742-
),
743-
self.elaborator.array_subpath(self.path, i, size),
744-
)
745-
})
746-
.collect();
747-
748-
if fields.iter().any(|(_, path)| path.is_some()) {
732+
enum ProjectionKind<Path> {
733+
Drop(std::ops::Range<u64>),
734+
Keep(u64, Path),
735+
}
736+
// Previously, we'd make a projection for every element in the array and create a drop
737+
// ladder if any `array_subpath` was `Some`, i.e. moving out with an array pattern.
738+
// This caused huge memory usage when generating the drops for large arrays, so we instead
739+
// record the *subslices* which are dropped and the *indexes* which are kept
740+
let mut drop_ranges = vec![];
741+
let mut dropping = true;
742+
let mut start = 0;
743+
for i in 0..size {
744+
let path = self.elaborator.array_subpath(self.path, i, size);
745+
if dropping && path.is_some() {
746+
drop_ranges.push(ProjectionKind::Drop(start..i));
747+
dropping = false;
748+
} else if !dropping && path.is_none() {
749+
dropping = true;
750+
start = i;
751+
}
752+
if let Some(path) = path {
753+
drop_ranges.push(ProjectionKind::Keep(i, path));
754+
}
755+
}
756+
if !drop_ranges.is_empty() {
757+
if dropping {
758+
drop_ranges.push(ProjectionKind::Drop(start..size));
759+
}
760+
let fields = drop_ranges
761+
.iter()
762+
.rev()
763+
.map(|p| {
764+
let (project, path) = match p {
765+
ProjectionKind::Drop(r) => (
766+
ProjectionElem::Subslice {
767+
from: r.start,
768+
to: r.end,
769+
from_end: false,
770+
},
771+
None,
772+
),
773+
&ProjectionKind::Keep(offset, path) => (
774+
ProjectionElem::ConstantIndex {
775+
offset,
776+
min_length: size,
777+
from_end: false,
778+
},
779+
Some(path),
780+
),
781+
};
782+
(tcx.mk_place_elem(self.place, project), path)
783+
})
784+
.collect::<Vec<_>>();
749785
let (succ, unwind) = self.drop_ladder_bottom();
750786
return self.drop_ladder(fields, succ, unwind).0;
751787
}
@@ -824,7 +860,7 @@ where
824860
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
825861
self.open_drop_for_array(*ety, size)
826862
}
827-
ty::Slice(ety) => self.open_drop_for_array(*ety, None),
863+
ty::Slice(ety) => self.drop_loop_pair(*ety),
828864

829865
_ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty),
830866
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// check-pass
2+
3+
const SZ: usize = 64_000_000;
4+
type BigDrop = [String; SZ];
5+
6+
fn f(_dropme: BigDrop) {}
7+
8+
fn f2(_moveme: BigDrop) -> String {
9+
let [a, ..] = _moveme;
10+
a
11+
}
12+
13+
fn main() {
14+
f(std::array::from_fn(|_| String::new()));
15+
f2(std::array::from_fn(|_| String::new()));
16+
}

0 commit comments

Comments
 (0)