@@ -280,37 +280,25 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
280
280
interp_ok ( match ( a, b) {
281
281
// Comparisons between integers are always known.
282
282
( Scalar :: Int ( a) , Scalar :: Int ( b) ) => ( a == b) as u8 ,
283
- // Comparisons of null with an arbitrary scalar can be known if `scalar_may_be_null`
284
- // indicates that the scalar can definitely *not* be null.
285
- ( Scalar :: Int ( int ) , ptr ) | ( ptr , Scalar :: Int ( int ) )
286
- if int . is_null ( ) && ! self . scalar_may_be_null ( ptr ) ? =>
287
- {
288
- 0
289
- }
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 .
283
+ // A pointer can be known to be unequal to an integer if them being equal would imply
284
+ // that the null pointer is in-bounds (including one-past-the-end) of the pointer's
285
+ // allocation (as the null pointer is never in-bounds of any allocation), or is
286
+ // misaligned (as `0` is a multiple of any alignment), or that the pointer's
287
+ // allocation would wrap around the address space.
288
+ // Concretely, if `scalar_may_be_null` indicates that `ptr.wrapping_sub(int)` cannot
289
+ // be equal to `0`, then we know that `ptr != int`.
290
+ // For the specific case where `int == 0`, this checks if the pointer itself
291
+ // can definitely not be null, and this behavior is exposed on stable as
292
+ // `pointer::is_null` .
293
293
( Scalar :: Int ( int) , Scalar :: Ptr ( ptr, _) ) | ( Scalar :: Ptr ( ptr, _) , Scalar :: Int ( int) ) => {
294
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.
295
+ let offset_ptr = ptr. wrapping_offset ( Size :: from_bytes ( int. wrapping_neg ( ) ) , self ) ;
296
+ if !self . scalar_may_be_null ( Scalar :: from_pointer ( offset_ptr, self ) ) ? {
297
+ // `ptr.wrapping_sub(int)` is definitely not equal to `0`, so `ptr != int`
309
298
0
310
299
} 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.
300
+ // `ptr.wrapping_sub(int)` could be equal to `0`, but might not be,
301
+ // so we cannot know for sure if `ptr == int` or not
314
302
2
315
303
}
316
304
}
0 commit comments