about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs25
-rw-r--r--src/test/ui/consts/offset_from.rs6
-rw-r--r--src/test/ui/consts/offset_from_ub.rs18
-rw-r--r--src/test/ui/consts/offset_from_ub.stderr47
4 files changed, 85 insertions, 11 deletions
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index c08e4c89609..04032847385 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -251,8 +251,28 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             "ptr_offset_from" => {
-                let a = self.read_immediate(args[0])?.to_scalar()?.to_ptr()?;
-                let b = self.read_immediate(args[1])?.to_scalar()?.to_ptr()?;
+                let isize_layout = self.layout_of(self.tcx.types.isize)?;
+                let a = self.read_immediate(args[0])?.to_scalar()?;
+                let b = self.read_immediate(args[1])?.to_scalar()?;
+
+                // Special case: if both scalars are *equal integers*
+                // and not NULL, we pretend there is an allocation of size 0 right there,
+                // and their offset is 0. (There's never a valid object at NULL, making it an
+                // exception from the exception.)
+                // This is the dual to the special exception for offset-by-0
+                // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
+                if a.is_bits() && b.is_bits() {
+                    let a = a.to_usize(self)?;
+                    let b = b.to_usize(self)?;
+                    if a == b && a != 0 {
+                        self.write_scalar(Scalar::from_int(0, isize_layout.size), dest)?;
+                        return Ok(true);
+                    }
+                }
+
+                // General case: we need two pointers.
+                let a = self.force_ptr(a)?;
+                let b = self.force_ptr(b)?;
                 if a.alloc_id != b.alloc_id {
                     throw_ub_format!(
                         "ptr_offset_from cannot compute offset of pointers into different \
@@ -266,7 +286,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     BinOp::Sub, a_offset, b_offset,
                 )?;
                 let pointee_layout = self.layout_of(substs.type_at(0))?;
-                let isize_layout = self.layout_of(self.tcx.types.isize)?;
                 let val = ImmTy::from_scalar(val, isize_layout);
                 let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
                 self.exact_div(val, size, dest)?;
diff --git a/src/test/ui/consts/offset_from.rs b/src/test/ui/consts/offset_from.rs
index 4d680068188..8c1b2784262 100644
--- a/src/test/ui/consts/offset_from.rs
+++ b/src/test/ui/consts/offset_from.rs
@@ -40,8 +40,14 @@ pub const OVERFLOW: isize = {
     unsafe { (base_ptr as *const u8).offset_from(field_ptr) }
 };
 
+pub const OFFSET_EQUAL_INTS: isize = {
+    let ptr = 1 as *const u8;
+    unsafe { ptr.offset_from(ptr) }
+};
+
 fn main() {
     assert_eq!(OFFSET, 0);
     assert_eq!(OFFSET_2, 1);
     assert_eq!(OVERFLOW, -1);
+    assert_eq!(OFFSET_EQUAL_INTS, 0);
 }
diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs
index 18b4d727126..c9030915620 100644
--- a/src/test/ui/consts/offset_from_ub.rs
+++ b/src/test/ui/consts/offset_from_ub.rs
@@ -25,13 +25,25 @@ pub const NOT_PTR: usize = {
     unsafe { (42 as *const u8).offset_from(&5u8) as usize }
 };
 
-pub const NOT_MULTIPLE_OF_SIZE: usize = {
+pub const NOT_MULTIPLE_OF_SIZE: isize = {
     //~^ NOTE
     let data = [5u8, 6, 7];
     let base_ptr = data.as_ptr();
     let field_ptr = &data[1] as *const u8 as *const u16;
-    let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) };
-    offset as usize
+    unsafe { field_ptr.offset_from(base_ptr as *const u16) }
+};
+
+pub const OFFSET_FROM_NULL: isize = {
+    //~^ NOTE
+    let ptr = 0 as *const u8;
+    unsafe { ptr.offset_from(ptr) }
+};
+
+pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
+    //~^ NOTE
+    let ptr1 = 8 as *const u8;
+    let ptr2 = 16 as *const u8;
+    unsafe { ptr2.offset_from(ptr1) }
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr
index 289128b4a17..1bd09034bfc 100644
--- a/src/test/ui/consts/offset_from_ub.stderr
+++ b/src/test/ui/consts/offset_from_ub.stderr
@@ -44,18 +44,55 @@ LL |           intrinsics::ptr_offset_from(self, origin)
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           exact_div: 1 cannot be divided by 2 without remainder
-   |           inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:27
+   |           inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:14
    | 
   ::: $DIR/offset_from_ub.rs:28:1
    |
-LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = {
+LL | / pub const NOT_MULTIPLE_OF_SIZE: isize = {
 LL | |
 LL | |     let data = [5u8, 6, 7];
 LL | |     let base_ptr = data.as_ptr();
-...  |
-LL | |     offset as usize
+LL | |     let field_ptr = &data[1] as *const u8 as *const u16;
+LL | |     unsafe { field_ptr.offset_from(base_ptr as *const u16) }
+LL | | };
+   | |__-
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL |           intrinsics::ptr_offset_from(self, origin)
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           |
+   |           invalid use of NULL pointer
+   |           inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:39:14
+   | 
+  ::: $DIR/offset_from_ub.rs:36:1
+   |
+LL | / pub const OFFSET_FROM_NULL: isize = {
+LL | |
+LL | |     let ptr = 0 as *const u8;
+LL | |     unsafe { ptr.offset_from(ptr) }
+LL | | };
+   | |__-
+
+error: any use of this value will cause an error
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL |           intrinsics::ptr_offset_from(self, origin)
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           |
+   |           a memory access tried to interpret some bytes as a pointer
+   |           inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:46:14
+   | 
+  ::: $DIR/offset_from_ub.rs:42:1
+   |
+LL | / pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
+LL | |
+LL | |     let ptr1 = 8 as *const u8;
+LL | |     let ptr2 = 16 as *const u8;
+LL | |     unsafe { ptr2.offset_from(ptr1) }
 LL | | };
    | |__-
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors