Skip to content

Commit 3c5b8e1

Browse files
committed
Explain why the two alloc_from_iter functions are so different.
1 parent e0d7ed1 commit 3c5b8e1

File tree

1 file changed

+16
-2
lines changed
  • compiler/rustc_arena/src

1 file changed

+16
-2
lines changed

compiler/rustc_arena/src/lib.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ where
155155
// This default collects into a `SmallVec` and then allocates by copying
156156
// from it. The specializations below for types like `Vec` are more
157157
// efficient, copying directly without the intermediate collecting step.
158-
// This default could be made more efficient, like
159-
// `DroplessArena::alloc_from_iter`, but it's not hot enough to bother.
160158
#[inline]
161159
default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
160+
// Safety: if iteration panics, `self` is untouched, and thus left in a
161+
// good state.
162162
let vec: SmallVec<[_; 8]> = self.into_iter().collect();
163163
vec.alloc_from_iter(arena)
164164
}
@@ -270,6 +270,20 @@ impl<T> TypedArena<T> {
270270

271271
#[inline]
272272
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
273+
// This implementation is entirely separate to
274+
// `DroplessIterator::alloc_from_iter`, even though conceptually they
275+
// are the same.
276+
//
277+
// `DroplessIterator` (in the fast case) writes elements from the
278+
// iterator one at a time into the allocated memory. That's easy
279+
// because the elements don't implement `Drop`. But for `TypedArena`
280+
// they do implement `Drop`, which means that if the iterator panics we
281+
// could end up with some allocated-but-uninitialized elements, which
282+
// will then cause UB in `TypedArena::drop`.
283+
//
284+
// Instead we use an approach where any iterator panic will occur
285+
// before the memory is allocated, with some specialization for common
286+
// cases like `Vec` and `SmallVec`.
273287
assert!(mem::size_of::<T>() != 0);
274288
iter.alloc_from_iter(self)
275289
}

0 commit comments

Comments
 (0)