Change:
Attempting to compile this code causes extremely large memory usage by rustc. By experimentation, the important features of the code are: large , the element type needs to have drop glue, and the drop can't be skipped with or some other mechanism. It also must be a program, not a library function. The problematic compiler invocation: . I expected to see this happen: The compiler memory usage shouldn't run away due to large ; in fact the compiler memory usage should be almost entirely independent of for this program. Instead, this happened: When is large, uses a lot of memory and takes a long time. I have not successfully compiled the above program with the given of 64M. I repro'd this on , , and finally: (I did not capture a compiler backtrace.) I surmise that there's a correlation between and compiler behavior but I haven't explored it beyond verifying a small doesn't repro the bad behavior. I thought perhaps this program tries to use the stack for the slice-array cast, and somehow the compiler is getting stuck on such a large stack frame. Thankfully, this is ruled out by checking that does indeed do the slice-array cast entirely using pointers. So the compiler shouldn't "see" how big the array is; it's behind a pointer. Appending to bypasses the issue, so it appears to be drop glue for the box which causes the problem. I don't see a particular reason why the drop glue for this type should be problematic; it should be no different than dropping the initialized part of a large . </p</details
is what shows up in logging right before hanging + memory explodes seems to be the culprit. ...

Discussion:
let tcx = self.tcx(); if let Some(size) = opt_size { <del> 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()) { </del> <ins> 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<_>>(); </ins> let (succ, unwind) = self.drop_ladder_bottom(); return self.drop_ladder(fields, succ, unwind).0; }

let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env()); self.open_drop_for_array(*ety, size) } <del> ty::Slice(ety) => self.open_drop_for_array(*ety, None), </del> <ins> ty::Slice(ety) => self.drop_loop_pair(*ety), </ins> _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty), }

<ins> // 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())); } </ins>