@@ -155,10 +155,10 @@ where
155
155
// This default collects into a `SmallVec` and then allocates by copying
156
156
// from it. The specializations below for types like `Vec` are more
157
157
// 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.
160
158
#[ inline]
161
159
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.
162
162
let vec: SmallVec < [ _ ; 8 ] > = self . into_iter ( ) . collect ( ) ;
163
163
vec. alloc_from_iter ( arena)
164
164
}
@@ -270,6 +270,20 @@ impl<T> TypedArena<T> {
270
270
271
271
#[ inline]
272
272
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`.
273
287
assert ! ( mem:: size_of:: <T >( ) != 0 ) ;
274
288
iter. alloc_from_iter ( self )
275
289
}
0 commit comments