about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-09-08 18:59:30 +0200
committerRalf Jung <post@ralfj.de>2024-09-08 19:07:46 +0200
commit11d51aae863d46a73ad39ec607bd7592fdb836e3 (patch)
treec42390e46d97b7e37edb5e235af98075a19a7a33
parent7b18b3eb6d45efe45ecbe0b6043a1a93cef4a166 (diff)
downloadrust-11d51aae863d46a73ad39ec607bd7592fdb836e3.tar.gz
rust-11d51aae863d46a73ad39ec607bd7592fdb836e3.zip
const: make ptr.is_null() stop execution on ambiguity
-rw-r--r--library/core/src/ptr/const_ptr.rs10
-rw-r--r--library/core/src/ptr/mut_ptr.rs17
-rw-r--r--tests/ui/consts/const-ptr-is-null.rs20
-rw-r--r--tests/ui/consts/const-ptr-is-null.stderr19
4 files changed, 46 insertions, 20 deletions
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 3b635e2a4aa..febb3fed963 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -40,15 +40,17 @@ impl<T: ?Sized> *const T {
 
         #[inline]
         const fn const_impl(ptr: *const u8) -> bool {
-            // Compare via a cast to a thin pointer, so fat pointers are only
-            // considering their "data" part for null-ness.
             match (ptr).guaranteed_eq(null_mut()) {
-                None => false,
                 Some(res) => res,
+                // To remain maximally convervative, we stop execution when we don't
+                // know whether the pointer is null or not.
+                // We can *not* return `false` here, that would be unsound in `NonNull::new`!
+                None => panic!("null-ness of this pointer cannot be determined in const context"),
             }
         }
 
-        #[allow(unused_unsafe)]
+        // Compare via a cast to a thin pointer, so fat pointers are only
+        // considering their "data" part for null-ness.
         const_eval_select((self as *const u8,), const_impl, runtime_impl)
     }
 
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 42975cc927b..bebc4b2f271 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -33,22 +33,7 @@ impl<T: ?Sized> *mut T {
     #[rustc_diagnostic_item = "ptr_is_null"]
     #[inline]
     pub const fn is_null(self) -> bool {
-        #[inline]
-        fn runtime_impl(ptr: *mut u8) -> bool {
-            ptr.addr() == 0
-        }
-
-        #[inline]
-        const fn const_impl(ptr: *mut u8) -> bool {
-            // Compare via a cast to a thin pointer, so fat pointers are only
-            // considering their "data" part for null-ness.
-            match (ptr).guaranteed_eq(null_mut()) {
-                None => false,
-                Some(res) => res,
-            }
-        }
-
-        const_eval_select((self as *mut u8,), const_impl, runtime_impl)
+        self.cast_const().is_null()
     }
 
     /// Casts to a pointer of another type.
diff --git a/tests/ui/consts/const-ptr-is-null.rs b/tests/ui/consts/const-ptr-is-null.rs
new file mode 100644
index 00000000000..82c293c0ad6
--- /dev/null
+++ b/tests/ui/consts/const-ptr-is-null.rs
@@ -0,0 +1,20 @@
+#![feature(const_ptr_is_null)]
+use std::ptr;
+
+const IS_NULL: () = {
+    assert!(ptr::null::<u8>().is_null());
+};
+const IS_NOT_NULL: () = {
+    assert!(!ptr::null::<u8>().wrapping_add(1).is_null());
+};
+
+const MAYBE_NULL: () = {
+    let x = 15;
+    let ptr = &x as *const i32;
+    // This one is still unambiguous...
+    assert!(!ptr.is_null());
+    // but once we shift outside the allocation, we might become null.
+    assert!(!ptr.wrapping_sub(512).is_null()); //~inside `MAYBE_NULL`
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr
new file mode 100644
index 00000000000..20e44a1401f
--- /dev/null
+++ b/tests/ui/consts/const-ptr-is-null.stderr
@@ -0,0 +1,19 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+   = note: the evaluated program panicked at 'null-ness of this pointer cannot be determined in const context', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+note: inside `std::ptr::const_ptr::<impl *const T>::is_null::const_impl`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `MAYBE_NULL`
+  --> $DIR/const-ptr-is-null.rs:17:14
+   |
+LL |     assert!(!ptr.wrapping_sub(512).is_null());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.