@@ -280,37 +280,25 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
280280 interp_ok ( match ( a, b) {
281281 // Comparisons between integers are always known.
282282 ( 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` .
293293 ( Scalar :: Int ( int) , Scalar :: Ptr ( ptr, _) ) | ( Scalar :: Ptr ( ptr, _) , Scalar :: Int ( int) ) => {
294294 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`
309298 0
310299 } 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
314302 2
315303 }
316304 }
0 commit comments