Skip to content

Commit d1196da

Browse files
committed
Offsetting pointers to zst is a nop
1 parent dfbe7f7 commit d1196da

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

src/eval_context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
893893
}
894894
// FIXME: assuming here that type size is < i64::max_value()
895895
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
896+
if pointee_size == 0 {
897+
// rustc relies on offsetting pointers to zsts to be a nop
898+
return Ok(ptr);
899+
}
896900
return if let Some(offset) = offset.checked_mul(pointee_size) {
897901
let ptr = ptr.signed_offset(offset, self.memory.layout)?;
898902
self.memory.check_bounds(ptr.to_ptr()?, false)?;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: -C debug-assertions
12+
13+
#![feature(iter_to_slice)]
14+
15+
use std::slice;
16+
17+
fn foo<T>(v: &[T]) -> Option<&[T]> {
18+
let mut it = v.iter();
19+
for _ in 0..5 {
20+
let _ = it.next();
21+
}
22+
Some(it.as_slice())
23+
}
24+
25+
fn foo_mut<T>(v: &mut [T]) -> Option<&mut [T]> {
26+
let mut it = v.iter_mut();
27+
for _ in 0..5 {
28+
let _ = it.next();
29+
}
30+
Some(it.into_slice())
31+
}
32+
33+
pub fn main() {
34+
// In a slice of zero-size elements the pointer is meaningless.
35+
// Ensure iteration still works even if the pointer is at the end of the address space.
36+
let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) };
37+
assert_eq!(slice.len(), 10);
38+
assert_eq!(slice.iter().count(), 10);
39+
40+
// .nth() on the iterator should also behave correctly
41+
let mut it = slice.iter();
42+
assert!(it.nth(5).is_some());
43+
assert_eq!(it.count(), 4);
44+
45+
// Converting Iter to a slice should never have a null pointer
46+
assert!(foo(slice).is_some());
47+
48+
// Test mutable iterators as well
49+
let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) };
50+
assert_eq!(slice.len(), 10);
51+
assert_eq!(slice.iter_mut().count(), 10);
52+
53+
{
54+
let mut it = slice.iter_mut();
55+
assert!(it.nth(5).is_some());
56+
assert_eq!(it.count(), 4);
57+
}
58+
59+
assert!(foo_mut(slice).is_some())
60+
}

0 commit comments

Comments
 (0)