Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute more pointer comparisons in CTFE #113052

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Comment on lines +326 to +328
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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.
// 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 -- hence we check `get_alloc_info`
// to exclude those cases.


// 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,
})
}
}
Expand Down
25 changes: 20 additions & 5 deletions tests/ui/consts/ptr_comparisons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
)]

const FOO: &usize = &42;
const BAR: &usize = &43;

fn foo() {}
fn bar() {}

macro_rules! check {
(eq, $a:expr, $b:expr) => {
Expand All @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/consts/ptr_comparisons.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ error[E0080]: evaluation of constant value failed
note: inside `ptr::const_ptr::<impl *const usize>::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
Expand All @@ -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
Expand Down