Skip to content

Commit 8c3296e

Browse files
committed
Remove an unnecessary test in grow_{amortized,exact}().
As long as these functions are called after `needs_to_grow()`, the capacity overflow check has the same result as the special zero-sized type check. This commit removes that check, documents the `needs_to_grow()` constraint, and updates the test accordingly.
1 parent 6bda5b3 commit 8c3296e

File tree

2 files changed

+38
-15
lines changed

2 files changed

+38
-15
lines changed

library/alloc/src/raw_vec.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ impl<T, A: Allocator> RawVec<T, A> {
370370
self.cap = Self::capacity_from_bytes(ptr.len());
371371
}
372372

373+
// This method must only be called after `needs_to_grow(len, additional)`
374+
// succeeds. Otherwise, if `T` is zero-sized it will cause a divide by
375+
// zero.
376+
//
373377
// This method is usually instantiated many times. So we want it to be as
374378
// small as possible, to improve compile times. But we also want as much of
375379
// its contents to be statically computable as possible, to make the
@@ -381,13 +385,9 @@ impl<T, A: Allocator> RawVec<T, A> {
381385
// This is ensured by the calling contexts.
382386
debug_assert!(additional > 0);
383387

384-
if mem::size_of::<T>() == 0 {
385-
// Since we return a capacity of `usize::MAX` when `elem_size` is
386-
// 0, getting to here necessarily means the `RawVec` is overfull.
387-
return Err(CapacityOverflow.into());
388-
}
389-
390-
// Nothing we can really do about these checks, sadly.
388+
// Nothing we can really do about these checks, sadly. (If this method
389+
// is called for a zero-sized `T` after `needs_to_grow()` has
390+
// succeeded, this early return will occur.)
391391
let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
392392

393393
// This guarantees exponential growth. The doubling cannot overflow
@@ -403,16 +403,17 @@ impl<T, A: Allocator> RawVec<T, A> {
403403
Ok(())
404404
}
405405

406+
// This method must only be called after `needs_to_grow(len, additional)`
407+
// succeeds. Otherwise, if `T` is zero-sized it will cause a divide by
408+
// zero.
409+
//
406410
// The constraints on this method are much the same as those on
407411
// `grow_amortized`, but this method is usually instantiated less often so
408412
// it's less critical.
409413
fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
410-
if mem::size_of::<T>() == 0 {
411-
// Since we return a capacity of `usize::MAX` when the type size is
412-
// 0, getting to here necessarily means the `RawVec` is overfull.
413-
return Err(CapacityOverflow.into());
414-
}
415-
414+
// Nothing we can really do about these checks, sadly. (If this method
415+
// is called for a zero-sized `T` after `needs_to_grow()` has
416+
// succeeded, this early return will occur.)
416417
let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
417418
let new_layout = Layout::array::<T>(cap);
418419

library/alloc/src/raw_vec/tests.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ fn zst() {
135135
assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
136136
zst_sanity(&v);
137137

138-
assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err);
138+
//v.grow_amortized(100, usize::MAX - 100); // panics, in `zst_grow_amortized_panic` below
139139
assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err);
140140
zst_sanity(&v);
141141

142-
assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err);
142+
//v.grow_exact(100, usize::MAX - 100); // panics, in `zst_grow_exact_panic` below
143143
assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err);
144144
zst_sanity(&v);
145145
}
@@ -161,3 +161,25 @@ fn zst_reserve_exact_panic() {
161161

162162
v.reserve_exact(101, usize::MAX - 100);
163163
}
164+
165+
#[test]
166+
#[should_panic(expected = "divide by zero")]
167+
fn zst_grow_amortized_panic() {
168+
let mut v: RawVec<ZST> = RawVec::new();
169+
zst_sanity(&v);
170+
171+
// This shows the divide by zero that occurs when `grow_amortized()` is
172+
// called when `needs_to_grow()` would have returned `false`.
173+
let _ = v.grow_amortized(100, usize::MAX - 100);
174+
}
175+
176+
#[test]
177+
#[should_panic(expected = "divide by zero")]
178+
fn zst_grow_exact_panic() {
179+
let mut v: RawVec<ZST> = RawVec::new();
180+
zst_sanity(&v);
181+
182+
// This shows the divide by zero that occurs when `grow_amortized()` is
183+
// called when `needs_to_grow()` would have returned `false`.
184+
let _ = v.grow_exact(100, usize::MAX - 100);
185+
}

0 commit comments

Comments
 (0)