Skip to content

Commit cbd9361

Browse files
authored
Rollup merge of #155326 - nnethercote:disallow-ZST-TypedArena, r=Nadrieril
Disallow ZST allocations with `TypedArena`. `DroplessArena::alloc` already disallows ZST allocation. `TypedArena::alloc` allows it but: - (a) it's never used, and - (b) writing to `NonNull::dangling()` seems dubious, even if the write is zero-sized. This commit just changes it to panic on a ZST. This eliminates an untested code path, and we shouldn't be allocating ZSTs anyway. It also eliminates an unused ZST code path in `clear_last_chunk`. r? @Nadrieril
2 parents c812064 + 3ce3436 commit cbd9361

2 files changed

Lines changed: 15 additions & 39 deletions

File tree

compiler/rustc_arena/src/lib.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -140,25 +140,19 @@ impl<T> TypedArena<T> {
140140
/// Allocates an object in the `TypedArena`, returning a reference to it.
141141
#[inline]
142142
pub fn alloc(&self, object: T) -> &mut T {
143+
assert!(size_of::<T>() != 0);
144+
143145
if self.ptr == self.end {
144146
self.grow(1)
145147
}
146148

147149
unsafe {
148-
if size_of::<T>() == 0 {
149-
self.ptr.set(self.ptr.get().wrapping_byte_add(1));
150-
let ptr = ptr::NonNull::<T>::dangling().as_ptr();
151-
// Don't drop the object. This `write` is equivalent to `forget`.
152-
ptr::write(ptr, object);
153-
&mut *ptr
154-
} else {
155-
let ptr = self.ptr.get();
156-
// Advance the pointer.
157-
self.ptr.set(self.ptr.get().add(1));
158-
// Write into uninitialized memory.
159-
ptr::write(ptr, object);
160-
&mut *ptr
161-
}
150+
let ptr = self.ptr.get();
151+
// Advance the pointer.
152+
self.ptr.set(self.ptr.get().add(1));
153+
// Write into uninitialized memory.
154+
ptr::write(ptr, object);
155+
&mut *ptr
162156
}
163157
}
164158

@@ -302,16 +296,10 @@ impl<T> TypedArena<T> {
302296
let end = self.ptr.get().addr();
303297
// We then calculate the number of elements to be dropped in the last chunk,
304298
// which is the filled area's length.
305-
let diff = if size_of::<T>() == 0 {
306-
// `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
307-
// the number of zero-sized values in the last and only chunk, just out of caution.
308-
// Recall that `end` was incremented for each allocated value.
309-
end - start
310-
} else {
311-
// FIXME: this should *likely* use `offset_from`, but more
312-
// investigation is needed (including running tests in miri).
313-
(end - start) / size_of::<T>()
314-
};
299+
assert_ne!(size_of::<T>(), 0);
300+
// FIXME: this should *likely* use `offset_from`, but more
301+
// investigation is needed (including running tests in miri).
302+
let diff = (end - start) / size_of::<T>();
315303
// Pass that to the `destroy` method.
316304
unsafe {
317305
last_chunk.destroy(diff);

compiler/rustc_arena/src/tests.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ impl<T> TypedArena<T> {
2222
if let Some(last_chunk) = chunks_borrow.last_mut() {
2323
self.clear_last_chunk(last_chunk);
2424
let len = chunks_borrow.len();
25-
// If `T` is ZST, code below has no effect.
2625
for mut chunk in chunks_borrow.drain(..len - 1) {
2726
chunk.destroy(chunk.entries);
2827
}
@@ -117,18 +116,6 @@ fn test_noncopy() {
117116
}
118117
}
119118

120-
#[test]
121-
fn test_typed_arena_zero_sized() {
122-
let arena = TypedArena::default();
123-
#[cfg(not(miri))]
124-
const N: usize = 100000;
125-
#[cfg(miri)]
126-
const N: usize = 1000;
127-
for _ in 0..N {
128-
arena.alloc(());
129-
}
130-
}
131-
132119
#[test]
133120
fn test_typed_arena_clear() {
134121
let mut arena = TypedArena::default();
@@ -207,7 +194,8 @@ thread_local! {
207194
static DROP_COUNTER: Cell<u32> = Cell::new(0)
208195
}
209196

210-
struct SmallDroppable;
197+
#[allow(unused)]
198+
struct SmallDroppable(u8);
211199

212200
impl Drop for SmallDroppable {
213201
fn drop(&mut self) {
@@ -222,7 +210,7 @@ fn test_typed_arena_drop_small_count() {
222210
let arena: TypedArena<SmallDroppable> = TypedArena::default();
223211
for _ in 0..100 {
224212
// Allocate something with drop glue to make sure it doesn't leak.
225-
arena.alloc(SmallDroppable);
213+
arena.alloc(SmallDroppable(0));
226214
}
227215
// dropping
228216
};

0 commit comments

Comments
 (0)