]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_arena/src/lib.rs
Rollup merge of #90652 - matthiaskrgr:unnnec_filter_map, r=jyn514
[rust.git] / compiler / rustc_arena / src / lib.rs
1 //! The arena, a fast but limited type of allocator.
2 //!
3 //! Arenas are a type of allocator that destroy the objects within, all at
4 //! once, once the arena itself is destroyed. They do not support deallocation
5 //! of individual objects while the arena itself is still alive. The benefit
6 //! of an arena is very fast allocation; just a pointer bump.
7 //!
8 //! This crate implements several kinds of arena.
9
10 #![doc(
11     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
12     test(no_crate_inject, attr(deny(warnings)))
13 )]
14 #![feature(dropck_eyepatch)]
15 #![feature(new_uninit)]
16 #![feature(maybe_uninit_slice)]
17 #![feature(min_specialization)]
18 #![feature(decl_macro)]
19 #![feature(rustc_attrs)]
20 #![cfg_attr(test, feature(test))]
21
22 use rustc_data_structures::sync;
23 use smallvec::SmallVec;
24
25 use std::alloc::Layout;
26 use std::cell::{Cell, RefCell};
27 use std::cmp;
28 use std::marker::{PhantomData, Send};
29 use std::mem::{self, MaybeUninit};
30 use std::ptr;
31 use std::slice;
32
33 #[inline(never)]
34 #[cold]
35 fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
36     f()
37 }
38
39 /// An arena that can hold objects of only one type.
40 pub struct TypedArena<T> {
41     /// A pointer to the next object to be allocated.
42     ptr: Cell<*mut T>,
43
44     /// A pointer to the end of the allocated area. When this pointer is
45     /// reached, a new chunk is allocated.
46     end: Cell<*mut T>,
47
48     /// A vector of arena chunks.
49     chunks: RefCell<Vec<TypedArenaChunk<T>>>,
50
51     /// Marker indicating that dropping the arena causes its owned
52     /// instances of `T` to be dropped.
53     _own: PhantomData<T>,
54 }
55
56 struct TypedArenaChunk<T> {
57     /// The raw storage for the arena chunk.
58     storage: Box<[MaybeUninit<T>]>,
59     /// The number of valid entries in the chunk.
60     entries: usize,
61 }
62
63 impl<T> TypedArenaChunk<T> {
64     #[inline]
65     unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
66         TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
67     }
68
69     /// Destroys this arena chunk.
70     #[inline]
71     unsafe fn destroy(&mut self, len: usize) {
72         // The branch on needs_drop() is an -O1 performance optimization.
73         // Without the branch, dropping TypedArena<u8> takes linear time.
74         if mem::needs_drop::<T>() {
75             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len]));
76         }
77     }
78
79     // Returns a pointer to the first allocated object.
80     #[inline]
81     fn start(&mut self) -> *mut T {
82         MaybeUninit::slice_as_mut_ptr(&mut self.storage)
83     }
84
85     // Returns a pointer to the end of the allocated space.
86     #[inline]
87     fn end(&mut self) -> *mut T {
88         unsafe {
89             if mem::size_of::<T>() == 0 {
90                 // A pointer as large as possible for zero-sized elements.
91                 !0 as *mut T
92             } else {
93                 self.start().add(self.storage.len())
94             }
95         }
96     }
97 }
98
99 // The arenas start with PAGE-sized chunks, and then each new chunk is twice as
100 // big as its predecessor, up until we reach HUGE_PAGE-sized chunks, whereupon
101 // we stop growing. This scales well, from arenas that are barely used up to
102 // arenas that are used for 100s of MiBs. Note also that the chosen sizes match
103 // the usual sizes of pages and huge pages on Linux.
104 const PAGE: usize = 4096;
105 const HUGE_PAGE: usize = 2 * 1024 * 1024;
106
107 impl<T> Default for TypedArena<T> {
108     /// Creates a new `TypedArena`.
109     fn default() -> TypedArena<T> {
110         TypedArena {
111             // We set both `ptr` and `end` to 0 so that the first call to
112             // alloc() will trigger a grow().
113             ptr: Cell::new(ptr::null_mut()),
114             end: Cell::new(ptr::null_mut()),
115             chunks: RefCell::new(vec![]),
116             _own: PhantomData,
117         }
118     }
119 }
120
121 trait IterExt<T> {
122     fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T];
123 }
124
125 impl<I, T> IterExt<T> for I
126 where
127     I: IntoIterator<Item = T>,
128 {
129     #[inline]
130     default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
131         let vec: SmallVec<[_; 8]> = self.into_iter().collect();
132         vec.alloc_from_iter(arena)
133     }
134 }
135
136 impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> {
137     #[inline]
138     fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
139         let len = self.len();
140         if len == 0 {
141             return &mut [];
142         }
143         // Move the content to the arena by copying and then forgetting it
144         unsafe {
145             let start_ptr = arena.alloc_raw_slice(len);
146             self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len);
147             mem::forget(self);
148             slice::from_raw_parts_mut(start_ptr, len)
149         }
150     }
151 }
152
153 impl<T> IterExt<T> for Vec<T> {
154     #[inline]
155     fn alloc_from_iter(mut self, arena: &TypedArena<T>) -> &mut [T] {
156         let len = self.len();
157         if len == 0 {
158             return &mut [];
159         }
160         // Move the content to the arena by copying and then forgetting it
161         unsafe {
162             let start_ptr = arena.alloc_raw_slice(len);
163             self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
164             self.set_len(0);
165             slice::from_raw_parts_mut(start_ptr, len)
166         }
167     }
168 }
169
170 impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
171     #[inline]
172     fn alloc_from_iter(mut self, arena: &TypedArena<A::Item>) -> &mut [A::Item] {
173         let len = self.len();
174         if len == 0 {
175             return &mut [];
176         }
177         // Move the content to the arena by copying and then forgetting it
178         unsafe {
179             let start_ptr = arena.alloc_raw_slice(len);
180             self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
181             self.set_len(0);
182             slice::from_raw_parts_mut(start_ptr, len)
183         }
184     }
185 }
186
187 impl<T> TypedArena<T> {
188     /// Allocates an object in the `TypedArena`, returning a reference to it.
189     #[inline]
190     pub fn alloc(&self, object: T) -> &mut T {
191         if self.ptr == self.end {
192             self.grow(1)
193         }
194
195         unsafe {
196             if mem::size_of::<T>() == 0 {
197                 self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
198                 let ptr = mem::align_of::<T>() as *mut T;
199                 // Don't drop the object. This `write` is equivalent to `forget`.
200                 ptr::write(ptr, object);
201                 &mut *ptr
202             } else {
203                 let ptr = self.ptr.get();
204                 // Advance the pointer.
205                 self.ptr.set(self.ptr.get().offset(1));
206                 // Write into uninitialized memory.
207                 ptr::write(ptr, object);
208                 &mut *ptr
209             }
210         }
211     }
212
213     #[inline]
214     fn can_allocate(&self, additional: usize) -> bool {
215         let available_bytes = self.end.get() as usize - self.ptr.get() as usize;
216         let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap();
217         available_bytes >= additional_bytes
218     }
219
220     /// Ensures there's enough space in the current chunk to fit `len` objects.
221     #[inline]
222     fn ensure_capacity(&self, additional: usize) {
223         if !self.can_allocate(additional) {
224             self.grow(additional);
225             debug_assert!(self.can_allocate(additional));
226         }
227     }
228
229     #[inline]
230     unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
231         assert!(mem::size_of::<T>() != 0);
232         assert!(len != 0);
233
234         self.ensure_capacity(len);
235
236         let start_ptr = self.ptr.get();
237         self.ptr.set(start_ptr.add(len));
238         start_ptr
239     }
240
241     #[inline]
242     pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
243         assert!(mem::size_of::<T>() != 0);
244         iter.alloc_from_iter(self)
245     }
246
247     /// Grows the arena.
248     #[inline(never)]
249     #[cold]
250     fn grow(&self, additional: usize) {
251         unsafe {
252             // We need the element size to convert chunk sizes (ranging from
253             // PAGE to HUGE_PAGE bytes) to element counts.
254             let elem_size = cmp::max(1, mem::size_of::<T>());
255             let mut chunks = self.chunks.borrow_mut();
256             let mut new_cap;
257             if let Some(last_chunk) = chunks.last_mut() {
258                 // If a type is `!needs_drop`, we don't need to keep track of how many elements
259                 // the chunk stores - the field will be ignored anyway.
260                 if mem::needs_drop::<T>() {
261                     let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
262                     last_chunk.entries = used_bytes / mem::size_of::<T>();
263                 }
264
265                 // If the previous chunk's len is less than HUGE_PAGE
266                 // bytes, then this chunk will be least double the previous
267                 // chunk's size.
268                 new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2);
269                 new_cap *= 2;
270             } else {
271                 new_cap = PAGE / elem_size;
272             }
273             // Also ensure that this chunk can fit `additional`.
274             new_cap = cmp::max(additional, new_cap);
275
276             let mut chunk = TypedArenaChunk::<T>::new(new_cap);
277             self.ptr.set(chunk.start());
278             self.end.set(chunk.end());
279             chunks.push(chunk);
280         }
281     }
282
283     // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
284     // chunks.
285     fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
286         // Determine how much was filled.
287         let start = last_chunk.start() as usize;
288         // We obtain the value of the pointer to the first uninitialized element.
289         let end = self.ptr.get() as usize;
290         // We then calculate the number of elements to be dropped in the last chunk,
291         // which is the filled area's length.
292         let diff = if mem::size_of::<T>() == 0 {
293             // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
294             // the number of zero-sized values in the last and only chunk, just out of caution.
295             // Recall that `end` was incremented for each allocated value.
296             end - start
297         } else {
298             (end - start) / mem::size_of::<T>()
299         };
300         // Pass that to the `destroy` method.
301         unsafe {
302             last_chunk.destroy(diff);
303         }
304         // Reset the chunk.
305         self.ptr.set(last_chunk.start());
306     }
307 }
308
309 unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
310     fn drop(&mut self) {
311         unsafe {
312             // Determine how much was filled.
313             let mut chunks_borrow = self.chunks.borrow_mut();
314             if let Some(mut last_chunk) = chunks_borrow.pop() {
315                 // Drop the contents of the last chunk.
316                 self.clear_last_chunk(&mut last_chunk);
317                 // The last chunk will be dropped. Destroy all other chunks.
318                 for chunk in chunks_borrow.iter_mut() {
319                     chunk.destroy(chunk.entries);
320                 }
321             }
322             // Box handles deallocation of `last_chunk` and `self.chunks`.
323         }
324     }
325 }
326
327 unsafe impl<T: Send> Send for TypedArena<T> {}
328
329 pub struct DroplessArena {
330     /// A pointer to the start of the free space.
331     start: Cell<*mut u8>,
332
333     /// A pointer to the end of free space.
334     ///
335     /// The allocation proceeds from the end of the chunk towards the start.
336     /// When this pointer crosses the start pointer, a new chunk is allocated.
337     end: Cell<*mut u8>,
338
339     /// A vector of arena chunks.
340     chunks: RefCell<Vec<TypedArenaChunk<u8>>>,
341 }
342
343 unsafe impl Send for DroplessArena {}
344
345 impl Default for DroplessArena {
346     #[inline]
347     fn default() -> DroplessArena {
348         DroplessArena {
349             start: Cell::new(ptr::null_mut()),
350             end: Cell::new(ptr::null_mut()),
351             chunks: Default::default(),
352         }
353     }
354 }
355
356 impl DroplessArena {
357     #[inline(never)]
358     #[cold]
359     fn grow(&self, additional: usize) {
360         unsafe {
361             let mut chunks = self.chunks.borrow_mut();
362             let mut new_cap;
363             if let Some(last_chunk) = chunks.last_mut() {
364                 // There is no need to update `last_chunk.entries` because that
365                 // field isn't used by `DroplessArena`.
366
367                 // If the previous chunk's len is less than HUGE_PAGE
368                 // bytes, then this chunk will be least double the previous
369                 // chunk's size.
370                 new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2);
371                 new_cap *= 2;
372             } else {
373                 new_cap = PAGE;
374             }
375             // Also ensure that this chunk can fit `additional`.
376             new_cap = cmp::max(additional, new_cap);
377
378             let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
379             self.start.set(chunk.start());
380             self.end.set(chunk.end());
381             chunks.push(chunk);
382         }
383     }
384
385     /// Allocates a byte slice with specified layout from the current memory
386     /// chunk. Returns `None` if there is no free space left to satisfy the
387     /// request.
388     #[inline]
389     fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
390         let start = self.start.get() as usize;
391         let end = self.end.get() as usize;
392
393         let align = layout.align();
394         let bytes = layout.size();
395
396         let new_end = end.checked_sub(bytes)? & !(align - 1);
397         if start <= new_end {
398             let new_end = new_end as *mut u8;
399             self.end.set(new_end);
400             Some(new_end)
401         } else {
402             None
403         }
404     }
405
406     #[inline]
407     pub fn alloc_raw(&self, layout: Layout) -> *mut u8 {
408         assert!(layout.size() != 0);
409         loop {
410             if let Some(a) = self.alloc_raw_without_grow(layout) {
411                 break a;
412             }
413             // No free space left. Allocate a new chunk to satisfy the request.
414             // On failure the grow will panic or abort.
415             self.grow(layout.size());
416         }
417     }
418
419     #[inline]
420     pub fn alloc<T>(&self, object: T) -> &mut T {
421         assert!(!mem::needs_drop::<T>());
422
423         let mem = self.alloc_raw(Layout::for_value::<T>(&object)) as *mut T;
424
425         unsafe {
426             // Write into uninitialized memory.
427             ptr::write(mem, object);
428             &mut *mem
429         }
430     }
431
432     /// Allocates a slice of objects that are copied into the `DroplessArena`, returning a mutable
433     /// reference to it. Will panic if passed a zero-sized type.
434     ///
435     /// Panics:
436     ///
437     ///  - Zero-sized types
438     ///  - Zero-length slices
439     #[inline]
440     pub fn alloc_slice<T>(&self, slice: &[T]) -> &mut [T]
441     where
442         T: Copy,
443     {
444         assert!(!mem::needs_drop::<T>());
445         assert!(mem::size_of::<T>() != 0);
446         assert!(!slice.is_empty());
447
448         let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T;
449
450         unsafe {
451             mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
452             slice::from_raw_parts_mut(mem, slice.len())
453         }
454     }
455
456     #[inline]
457     unsafe fn write_from_iter<T, I: Iterator<Item = T>>(
458         &self,
459         mut iter: I,
460         len: usize,
461         mem: *mut T,
462     ) -> &mut [T] {
463         let mut i = 0;
464         // Use a manual loop since LLVM manages to optimize it better for
465         // slice iterators
466         loop {
467             let value = iter.next();
468             if i >= len || value.is_none() {
469                 // We only return as many items as the iterator gave us, even
470                 // though it was supposed to give us `len`
471                 return slice::from_raw_parts_mut(mem, i);
472             }
473             ptr::write(mem.add(i), value.unwrap());
474             i += 1;
475         }
476     }
477
478     #[inline]
479     pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
480         let iter = iter.into_iter();
481         assert!(mem::size_of::<T>() != 0);
482         assert!(!mem::needs_drop::<T>());
483
484         let size_hint = iter.size_hint();
485
486         match size_hint {
487             (min, Some(max)) if min == max => {
488                 // We know the exact number of elements the iterator will produce here
489                 let len = min;
490
491                 if len == 0 {
492                     return &mut [];
493                 }
494
495                 let mem = self.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
496                 unsafe { self.write_from_iter(iter, len, mem) }
497             }
498             (_, _) => {
499                 cold_path(move || -> &mut [T] {
500                     let mut vec: SmallVec<[_; 8]> = iter.collect();
501                     if vec.is_empty() {
502                         return &mut [];
503                     }
504                     // Move the content to the arena by copying it and then forgetting
505                     // the content of the SmallVec
506                     unsafe {
507                         let len = vec.len();
508                         let start_ptr =
509                             self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
510                         vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
511                         vec.set_len(0);
512                         slice::from_raw_parts_mut(start_ptr, len)
513                     }
514                 })
515             }
516         }
517     }
518 }
519
520 /// Calls the destructor for an object when dropped.
521 struct DropType {
522     drop_fn: unsafe fn(*mut u8),
523     obj: *mut u8,
524 }
525
526 // SAFETY: we require `T: Send` before type-erasing into `DropType`.
527 #[cfg(parallel_compiler)]
528 unsafe impl sync::Send for DropType {}
529
530 impl DropType {
531     #[inline]
532     unsafe fn new<T: sync::Send>(obj: *mut T) -> Self {
533         unsafe fn drop_for_type<T>(to_drop: *mut u8) {
534             std::ptr::drop_in_place(to_drop as *mut T)
535         }
536
537         DropType { drop_fn: drop_for_type::<T>, obj: obj as *mut u8 }
538     }
539 }
540
541 impl Drop for DropType {
542     fn drop(&mut self) {
543         unsafe { (self.drop_fn)(self.obj) }
544     }
545 }
546
547 /// An arena which can be used to allocate any type.
548 ///
549 /// # Safety
550 ///
551 /// Allocating in this arena is unsafe since the type system
552 /// doesn't know which types it contains. In order to
553 /// allocate safely, you must store a `PhantomData<T>`
554 /// alongside this arena for each type `T` you allocate.
555 #[derive(Default)]
556 pub struct DropArena {
557     /// A list of destructors to run when the arena drops.
558     /// Ordered so `destructors` gets dropped before the arena
559     /// since its destructor can reference memory in the arena.
560     destructors: RefCell<Vec<DropType>>,
561     arena: DroplessArena,
562 }
563
564 impl DropArena {
565     #[inline]
566     pub unsafe fn alloc<T>(&self, object: T) -> &mut T
567     where
568         T: sync::Send,
569     {
570         let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T;
571         // Write into uninitialized memory.
572         ptr::write(mem, object);
573         let result = &mut *mem;
574         // Record the destructor after doing the allocation as that may panic
575         // and would cause `object`'s destructor to run twice if it was recorded before.
576         self.destructors.borrow_mut().push(DropType::new(result));
577         result
578     }
579
580     #[inline]
581     pub unsafe fn alloc_from_iter<T, I>(&self, iter: I) -> &mut [T]
582     where
583         T: sync::Send,
584         I: IntoIterator<Item = T>,
585     {
586         let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
587         if vec.is_empty() {
588             return &mut [];
589         }
590         let len = vec.len();
591
592         let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
593
594         let mut destructors = self.destructors.borrow_mut();
595         // Reserve space for the destructors so we can't panic while adding them.
596         destructors.reserve(len);
597
598         // Move the content to the arena by copying it and then forgetting
599         // the content of the SmallVec.
600         vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
601         mem::forget(vec.drain(..));
602
603         // Record the destructors after doing the allocation as that may panic
604         // and would cause `object`'s destructor to run twice if it was recorded before.
605         for i in 0..len {
606             destructors.push(DropType::new(start_ptr.add(i)));
607         }
608
609         slice::from_raw_parts_mut(start_ptr, len)
610     }
611 }
612
613 pub macro arena_for_type {
614     ([][$ty:ty]) => {
615         $crate::TypedArena<$ty>
616     },
617     ([few $(, $attrs:ident)*][$ty:ty]) => {
618         ::std::marker::PhantomData<$ty>
619     },
620     ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
621         $crate::arena_for_type!([$($attrs),*]$args)
622     },
623 }
624
625 pub macro which_arena_for_type {
626     ([][$arena:expr]) => {
627         ::std::option::Option::Some($arena)
628     },
629     ([few$(, $attrs:ident)*][$arena:expr]) => {
630         ::std::option::Option::None
631     },
632     ([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
633         $crate::which_arena_for_type!([$($attrs),*]$args)
634     },
635 }
636
637 #[rustc_macro_transparency = "semitransparent"]
638 pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
639     #[derive(Default)]
640     pub struct Arena<$tcx> {
641         pub dropless: $crate::DroplessArena,
642         drop: $crate::DropArena,
643         $($name: $crate::arena_for_type!($a[$ty]),)*
644     }
645
646     pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
647         fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
648         fn allocate_from_iter<'a>(
649             arena: &'a Arena<'tcx>,
650             iter: impl ::std::iter::IntoIterator<Item = Self>,
651         ) -> &'a mut [Self];
652     }
653
654     impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
655         #[inline]
656         fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
657             arena.dropless.alloc(self)
658         }
659         #[inline]
660         fn allocate_from_iter<'a>(
661             arena: &'a Arena<'tcx>,
662             iter: impl ::std::iter::IntoIterator<Item = Self>,
663         ) -> &'a mut [Self] {
664             arena.dropless.alloc_from_iter(iter)
665         }
666
667     }
668     $(
669         impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
670             #[inline]
671             fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
672                 if !::std::mem::needs_drop::<Self>() {
673                     return arena.dropless.alloc(self);
674                 }
675                 match $crate::which_arena_for_type!($a[&arena.$name]) {
676                     ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
677                         ty_arena.alloc(self)
678                     }
679                     ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
680                 }
681             }
682
683             #[inline]
684             fn allocate_from_iter<'a>(
685                 arena: &'a Arena<$tcx>,
686                 iter: impl ::std::iter::IntoIterator<Item = Self>,
687             ) -> &'a mut [Self] {
688                 if !::std::mem::needs_drop::<Self>() {
689                     return arena.dropless.alloc_from_iter(iter);
690                 }
691                 match $crate::which_arena_for_type!($a[&arena.$name]) {
692                     ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
693                         ty_arena.alloc_from_iter(iter)
694                     }
695                     ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
696                 }
697             }
698         }
699     )*
700
701     impl<'tcx> Arena<'tcx> {
702         #[inline]
703         pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
704             value.allocate_on(self)
705         }
706
707         #[inline]
708         pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
709             if value.is_empty() {
710                 return &mut [];
711             }
712             self.dropless.alloc_slice(value)
713         }
714
715         pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
716             &'a self,
717             iter: impl ::std::iter::IntoIterator<Item = T>,
718         ) -> &'a mut [T] {
719             T::allocate_from_iter(self, iter)
720         }
721     }
722 }
723
724 #[cfg(test)]
725 mod tests;