Skip to content

Commit

Permalink
Drop subslices of arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
clubby789 committed Mar 17, 2023
1 parent 2d64f22 commit ce2d528
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 18 deletions.
72 changes: 54 additions & 18 deletions compiler/rustc_mir_dataflow/src/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,23 +729,59 @@ where
let tcx = self.tcx();

if let Some(size) = opt_size {
let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size)
.map(|i| {
(
tcx.mk_place_elem(
self.place,
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()) {
enum ProjectionKind<Path> {
Drop(std::ops::Range<u64>),
Keep(u64, Path),
}
// Previously, we'd make a projection for every element in the array and create a drop
// ladder if any `array_subpath` was `Some`, i.e. moving out with an array pattern.
// This caused huge memory usage when generating the drops for large arrays, so we instead
// record the *subslices* which are dropped and the *indexes* which are kept
let mut drop_ranges = vec![];
let mut dropping = true;
let mut start = 0;
for i in 0..size {
let path = self.elaborator.array_subpath(self.path, i, size);
if dropping && path.is_some() {
drop_ranges.push(ProjectionKind::Drop(start..i));
dropping = false;
} else if !dropping && path.is_none() {
dropping = true;
start = i;
}
if let Some(path) = path {
drop_ranges.push(ProjectionKind::Keep(i, path));
}
}
if !drop_ranges.is_empty() {
if dropping {
drop_ranges.push(ProjectionKind::Drop(start..size));
}
let fields = drop_ranges
.iter()
.rev()
.map(|p| {
let (project, path) = match p {
ProjectionKind::Drop(r) => (
ProjectionElem::Subslice {
from: r.start,
to: r.end,
from_end: false,
},
None,
),
&ProjectionKind::Keep(offset, path) => (
ProjectionElem::ConstantIndex {
offset,
min_length: size,
from_end: false,
},
Some(path),
),
};
(tcx.mk_place_elem(self.place, project), path)
})
.collect::<Vec<_>>();
let (succ, unwind) = self.drop_ladder_bottom();
return self.drop_ladder(fields, succ, unwind).0;
}
Expand Down Expand Up @@ -824,7 +860,7 @@ where
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
self.open_drop_for_array(*ety, size)
}
ty::Slice(ety) => self.open_drop_for_array(*ety, None),
ty::Slice(ety) => self.drop_loop_pair(*ety),

_ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty),
}
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/mir/issue-109004-drop-large-array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// check-pass

const SZ: usize = 64_000_000;
type BigDrop = [String; SZ];

fn f(_dropme: BigDrop) {}

fn f2(_moveme: BigDrop) -> String {
let [a, ..] = _moveme;
a
}

fn main() {
f(std::array::from_fn(|_| String::new()));
f2(std::array::from_fn(|_| String::new()));
}

0 comments on commit ce2d528

Please sign in to comment.