Skip to content

Commit 156113b

Browse files
committed
Implement another check in ptr_guaranteed_cmp in consteval:
When comparing a pointer with an integer(-valued pointer), if the integer and the pointer have a different residue modulo the pointer's allocation's alignment, they can never be equal. Else, we can't know.
1 parent d61c58a commit 156113b

File tree

1 file changed

+28
-3
lines changed
  • compiler/rustc_const_eval/src/const_eval

1 file changed

+28
-3
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,33 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
287287
{
288288
0
289289
}
290-
// Other ways of comparing integers and pointers can never be known for sure.
291-
(Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2,
290+
// Other ways of comparing integers and pointers can never be known for sure,
291+
// except for alignment, e.g. `1 as *const _` can never be equal to an even offset
292+
// in an `align(2)` allocation.
293+
(Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => {
294+
let int = int.to_target_usize(*self.tcx);
295+
let (ptr_prov, ptr_offset) = ptr.prov_and_relative_offset();
296+
let allocid = ptr_prov.alloc_id();
297+
let allocinfo = self.get_alloc_info(allocid);
298+
299+
// Check if the pointer cannot be equal to the integer due to alignment.
300+
// For this purpose, an integer can be thought of as an offset into a
301+
// maximally-aligned "allocation" (the whole address space),
302+
// so the least common alignment is the alignment of the pointer's allocation.
303+
let min_align = allocinfo.align.bytes();
304+
let ptr_residue = ptr_offset.bytes() % min_align;
305+
let int_residue = int % min_align;
306+
if ptr_residue != int_residue {
307+
// The pointer and integer have a different residue modulo their common
308+
// alignment, they can never be equal.
309+
0
310+
} else {
311+
// The pointer and integer have the same residue modulo their common alignment,
312+
// so the pointer could end up equal to the integer at runtime;
313+
// we can't know for sure.
314+
2
315+
}
316+
}
292317
(Scalar::Ptr(a, _), Scalar::Ptr(b, _)) => {
293318
let (a_prov, a_offset) = a.prov_and_relative_offset();
294319
let (b_prov, b_offset) = b.prov_and_relative_offset();
@@ -303,7 +328,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
303328
let a_residue = a_offset.bytes() % min_align;
304329
let b_residue = b_offset.bytes() % min_align;
305330
if a_residue != b_residue {
306-
// If the two pointers have a different residue from their
331+
// If the two pointers have a different residue modulo their
307332
// common alignment, they cannot be equal.
308333
return interp_ok(0);
309334
}

0 commit comments

Comments
 (0)