diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7391f5670400a..df2260df5e11d 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::errors::{LongRunning, LongRunningWarn}; use crate::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx, + self, compile_time_machine, AllocId, AllocKind, ConstAllocation, FnVal, Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, Scalar, }; use crate::{errors, fluent_generated as fluent}; @@ -322,13 +322,27 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { } // Equality with integers can never be known for sure. (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2, - // FIXME: return a `1` for when both sides are the same pointer, *except* that - // some things (like functions and vtables) do not have stable addresses - // so we need to be careful around them (see e.g. #73722). - // FIXME: return `0` for at least some comparisons where we can reliably - // determine the result of runtime inequality tests at compile-time. - // Examples include comparison of addresses in different static items. - (Scalar::Ptr(..), Scalar::Ptr(..)) => 2, + // Comparisons between data pointers are known if they point + // to the same allocation. Function pointers and vtables do not + // have stable addresses (see #73722), so the result of comparisons + // cannot be known during CTFE. + + // FIXME: return `0` for in-bounds pointers from different allocations + // when we can reliably tell that they do not overlap. + (Scalar::Ptr(a, _), Scalar::Ptr(b, _)) + if a.provenance == b.provenance + && matches!( + self.get_alloc_info(a.provenance).2, + AllocKind::LiveData | AllocKind::Dead + ) => + { + if a == b { + 1 + } else { + 0 + } + } + _ => 2, }) } } diff --git a/tests/ui/consts/ptr_comparisons.rs b/tests/ui/consts/ptr_comparisons.rs index f442e61383973..c83415ea8e598 100644 --- a/tests/ui/consts/ptr_comparisons.rs +++ b/tests/ui/consts/ptr_comparisons.rs @@ -10,6 +10,10 @@ )] const FOO: &usize = &42; +const BAR: &usize = &43; + +fn foo() {} +fn bar() {} macro_rules! check { (eq, $a:expr, $b:expr) => { @@ -31,13 +35,24 @@ check!(ne, 0, 1); check!(ne, FOO as *const _, 0); check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0); check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0); +check!(eq, FOO as *const _, FOO as *const _); +check!(ne, unsafe { (FOO as *const usize).offset(1) }, FOO as *const _); + +// Comparisons of pointers to different allocations cannot be computed in the +// general case, but some more cases could be implemented eventually: -// We want pointers to be equal to themselves, but aren't checking this yet because -// there are some open questions (e.g. whether function pointers to the same function -// compare equal, they don't necessarily at runtime). -// The case tested here should work eventually, but does not work yet. -check!(!, FOO as *const _, FOO as *const _); +// This could be known, because FOO points to different data than BAR, so the +// two pointers must be unequal. +check!(!, FOO as *const _, BAR as *const _); +// Function pointer addresses could overlap with the addresses of one-past-end-pointers +// so this check would need to be extra precise. +check!(!, foo as *const usize, FOO as *const _); +// This comparison cannot be known until the whole memory layout is, +// so it cannot be performed in CTFE. +check!(!, unsafe { (FOO as *const usize).offset(1) }, BAR as *const _); +// Function pointer comparions are flaky even at runtime. +check!(!, foo as *const usize, bar as *const usize); /////////////////////////////////////////////////////////////////////////////// // If any of the below start compiling, make sure to add a `check` test for it. diff --git a/tests/ui/consts/ptr_comparisons.stderr b/tests/ui/consts/ptr_comparisons.stderr index fea924d12e54e..29486530ca8e3 100644 --- a/tests/ui/consts/ptr_comparisons.stderr +++ b/tests/ui/consts/ptr_comparisons.stderr @@ -6,19 +6,19 @@ error[E0080]: evaluation of constant value failed note: inside `ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `_` - --> $DIR/ptr_comparisons.rs:50:34 + --> $DIR/ptr_comparisons.rs:65:34 | LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/ptr_comparisons.rs:53:33 + --> $DIR/ptr_comparisons.rs:68:33 | LL | unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed - --> $DIR/ptr_comparisons.rs:57:27 + --> $DIR/ptr_comparisons.rs:72:27 | LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -27,7 +27,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/ptr_comparisons.rs:61:27 + --> $DIR/ptr_comparisons.rs:76:27 | LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes