The Rust Strawberry test
One fine day at work, I came across a piece of code in Rust that looked like this:
fn main() {
// Will this panic or not?
let s : Vec<u8> = vec![0u8; 32];
println!("{:?}", &s[1..=0]);
}
Initially, I thought, Oh no, this will panic! So, I threw this sample into the Rust playground to test it out. And… it returned an empty slice!!! NO PANIC.
Let’s dig into why. &s[1..=0] breaks down into the SliceIndex implementation for RangeInclusive:
#![allow(unused)]
fn main() {
unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
type Output = [T];
#[inline]
fn get(self, slice: &[T]) -> Option<&[T]> {
if *self.end() == usize::MAX { None } else { self.into_slice_range().get(slice) }
}
#[inline]
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
if *self.end() == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
unsafe { self.into_slice_range().get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
unsafe { self.into_slice_range().get_unchecked_mut(slice) }
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
...
if end < len {
end = end + 1;
...
}
slice_index_fail(start, end, slice.len())
}
#[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
...
if end < len {
end = end + 1;
...
}
slice_index_fail(start, end, slice.len())
}
}
In this implementation, index and index_mut handle the end + 1, while the rest delegate it to into_slice_range, which handles it properly as well:
#![allow(unused)]
fn main() {
impl RangeInclusive<usize> {
#[inline]
pub(crate) const fn into_slice_range(self) -> Range<usize> {
let exclusive_end = self.end + 1;
let start = if self.exhausted { exclusive_end } else { self.start };
start..exclusive_end
}
}
}
So, in short, despite my intuition, this code is safe. ✅
But what do the LLMs think?
Well, the results reminded me of the infamous Strawberry incident. For the sake of uniformity, all prompts were tested using free accounts on their respective platforms.
| LLM | Panic or No Panic |
|---|---|
| ChatGPT | ✅ Panic |
| Claude | ✅ Panic |
| DeepSeek | ✅ Panic |
| Gemini | ❌ No Panic |
| Grok | ✅ Panic |
| Kimi K2.5 | ✅ Panic |
ChatGPT - Panic!
Yes — this will panic at runtime.
Why?
You created:
#![allow(unused)]
fn main() {
let s: Vec<u8> = vec![0u8; 32];
}
So s has length 32.
Then you slice it with:
#![allow(unused)]
fn main() {
&s[1..=0]
}
This is an inclusive range from index 1 to index 0.
That means:
- start = 1
- end = 0
- inclusive range (
..=)
In Rust, slicing requires:
start <= end + 1 (for inclusive ranges this effectively means start <= end)
But here:
1 > 0
So the range is invalid.
What happens?
Rust performs bounds checking at runtime for slices. Since the start index is greater than the end index, it triggers:
thread 'main' panicked at 'slice index starts at 1 but ends at 0'
Important Detail
Even though both indices (0 and 1) are individually valid indices for a 32-element vector, the range itself is invalid, which causes the panic.
Contrast Example (This does NOT panic)
#![allow(unused)]
fn main() {
&s[1..1] // empty slice, valid
}
This produces an empty slice because the start equals the end.
Final Answer
✅ Yes, it panics at runtime because the slice range 1..=0 is invalid (start > end).
Claude - Panic!
This code will panic at runtime.
Here’s why: &s[1..=0] is an inclusive range (notice the =), which means it’s trying to create a slice from index 1 up to and including index 0. This is logically impossible since you can’t have a range where the start index (1) is greater than the end index (0).
When you use an inclusive range start..=end, Rust requires that start <= end. In this case, 1 <= 0 is false, so the indexing operation will panic with an error like:
thread 'main' panicked at 'range start index 1 out of range for slice of length 0'
or similar message about the range being invalid.
If you wanted an empty slice, you could use:
&s[0..0](exclusive range, valid)&s[1..1](exclusive range, valid)
But &s[1..=0] is invalid because inclusive ranges cannot have start > end.
DeepSeek - Panic!
Let’s analyze this code step by step:
fn main() {
// Will this panic or not?
let s : Vec<u8> = vec![0u8; 32];
println!("{:?}", &s[1..=0]);
}
This code will panic at runtime.
Explanation:
The slice &s[1..=0] is trying to create a range from index 1 to index 0 (inclusive). This is an invalid range because:
1..=0means “from 1 up to and including 0”- This is impossible since the start index (1) is greater than the end index (0)
When Rust encounters an invalid range like this during indexing operations, it will panic with a message similar to:
thread 'main' panicked at 'slice index starts at 1 but ends at 0'
Important Note:
Even though the vector has 32 elements (indices 0-31), the slice operation fails before it even checks if the indices are within bounds. The range itself is invalid because start > end for an inclusive range.
The only non-panicking behavior with invalid ranges occurs with exclusive ranges (..) where an empty range is valid (e.g., &s[1..1] would give an empty slice without panicking).
Gemini - no Panic!
When I initially performed the test, Gemini did indeed say it would panic!. However, it was on an account whose settings did not allow me to share the chat, and repeating the test on new accounts has always yielded no panic. Interpret this however you will.
The short answer: No, it will not panic.
While it looks like you are trying to slice “backward” (from index 1 to 0), Rust handles this specific case gracefully because of how inclusive ranges work.
Why it works
In Rust, an inclusive range start..=end is considered empty if start > end. When you slice a Vec or a slice with an empty range, Rust returns an empty slice rather than panicking, provided the starting index is within the bounds of the container.
-
The Container:
shas a length of 2 (indices 0 and 1). -
The Slice:
&s[1..=0] -
The start index
1is less than or equal to the length of the vector, so the starting point is valid. -
Since
1 > 0, the range1..=0contains no elements. -
The Result: You get an empty slice:
[].
Comparison: When would it panic?
To give you some perspective, here is where the code would break:
| Scenario | Code | Result | Why? |
|---|---|---|---|
| Valid Empty Slice | &s[1..=0] | [] | Start index is within bounds; range is empty. |
| Out of Bounds | &s[3..=0] | Panic | The start index 3 is greater than the length 2. |
| Inclusive vs. Exclusive | &s[0..=2] | Panic | Index 2 is out of bounds for an inclusive range (max index is 1). |
Output
If you run your code, the console will print:
#![allow(unused)]
fn main() {
[]
}
Would you like to see how this behavior changes if you use an exclusive range like &s[1..0], or should we look at how to safely handle slicing with the .get() method?
Grok - Panic!
Yes, this code will panic.
The expression &s[1..=0] creates an invalid slice range in Rust.
Why it panics
In Rust, for a range start..=end (inclusive range):
- it is only valid when
start ≤ end - when
start > end, the range is empty — but only if you use..=with integers that satisfy start ≤ end + 1
But here:
#![allow(unused)]
fn main() {
1 ..= 0
}
→ 1 > 0
→ this is an invalid inclusive range
Rust does not allow creating an inclusive range where the start is greater than the end — it panics at runtime when you try to use it in a slice.
Quick comparison
#![allow(unused)]
fn main() {
&vec[1..0] // this is OK → empty slice (non-inclusive)
&vec[1..=0] // this PANICS (inclusive, but 1 > 0)
}
What actually happens
#![allow(unused)]
fn main() {
let s: Vec<u8> = vec![0u8; 32];
println!("{:?}", &s[1..=0]); // ← panic here
}
Output:
thread 'main' panicked at 'range start is greater than end'
(or very similar message depending on Rust version)
Correct ways to write an empty slice
#![allow(unused)]
fn main() {
&s[1..1] // classic way, always empty
&s[5..5]
&s[..0] // from beginning to 0 → empty
&vec![0u8;32][10..=9] // this also panics (same reason)
}
So short answer:
Yes — your code panics.
Because 1..=0 is an invalid inclusive range.
Want to see many ways to get empty slices safely? 😄
Kimi K2.5 - Panic!
This is an interesting Rust question about slice indexing behavior. Let me analyze this code without needing any tools.
Analysis
The code creates a vector of 32 zeros, then tries to print &s[1..=0].
The key question: Will this panic or not?
Answer: Yes, this will panic! 🚨
Here’s why:
The Range 1..=0 (Inclusive Range)
In Rust, range bounds have specific rules:
start..=endis an inclusive range- The critical rule: The
startmust be ≤endfor the range to be valid
When you write 1..=0:
- Start = 1
- End = 0 (inclusive)
Since 1 > 0, this violates the range invariant that start ≤ end.
What Happens
#![allow(unused)]
fn main() {
let s: Vec<u8> = vec![0u8; 32];
println!("{:?}", &s[1..=0]); // PANIC!
}
Panic message:
thread 'main' panicked at 'slice index starts at 1 but ends at 0'
Why Not an Empty Slice?
You might think “1 to 0 is just empty,” but Rust’s slice indexing doesn’t work that way. The bounds are checked before considering what elements would be selected. The range 1..=0 is considered invalid because:
- Start (1) > End (0)
- This is always an error, regardless of the vector’s contents
Contrast with Valid Empty Ranges
These would not panic (they produce empty slices):
#![allow(unused)]
fn main() {
&s[0..0] // start == end, valid empty range
&s[1..1] // start == end, valid empty range
&s[32..32] // start == end == len, valid empty range
&s[1..0] // wait... this also panics! (exclusive range with start > end)
}
Even 1..0 (exclusive) panics for the same reason.
Summary
| Expression | Result |
|---|---|
s[0..0] | ✅ Empty slice &[] |
s[1..1] | ✅ Empty slice &[] |
s[1..0] | ❌ Panic (start > end) |
s[1..=0] | ❌ Panic (start > end) |
The panic occurs because Rust validates that range bounds are logically ordered before applying them to the slice.