diff --git a/tests/ui/codegen/equal-pointers-unequal/README.md b/tests/ui/codegen/equal-pointers-unequal/README.md new file mode 100644 index 0000000000000..3e1d106862190 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/README.md @@ -0,0 +1,24 @@ +See https://github.com/rust-lang/rust/issues/107975 + +Basically, if you have two pointers with the same address +but from two different allocations, +and then you do something with their addresses as integers, +the compiler may make some very strange assumptions during the compilation, +resulting in some self-contradictory behavior of the compiled code. + +This folder contains some examples. +They all boil down to allocating a variable on the stack, taking its address, +getting rid of the variable, and then doing it all again. +This way we end up with two addresses stored in two `usize`s (`a` and `b`). +The addresses are (probably) equal but (definitely) come from two different allocations. +Logically, we would expect that exactly one of the following options holds true: +1. `a == b` +2. `a != b` +Sadly, the compiler does not always agree. + +Due to Rust having at least three meaningfully different ways +to get a variable's address as an `usize`, +each example is provided in three versions, each in the corresponding subfolder: +1. `./as-cast/` for `&v as *const _ as usize`, +2. `./strict-provenance/` for `addr_of!(v).addr()`, +2. `./exposed-provenance/` for `addr_of!(v).expose_provenance()`. diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/format.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/format.rs new file mode 100644 index 0000000000000..4ec8c61e2df67 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/format.rs @@ -0,0 +1,24 @@ +//@ run-pass +//@ known-bug: #107975 + +fn main() { + let a: usize = { + let v = 0u8; + &v as *const _ as usize + }; + let b: usize = { + let v = 0u8; + &v as *const _ as usize + }; + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // But they are not equal. + assert_ne!(a, b); + // But they are the same hex number. + assert_eq!(format!("{a:x}"), format!("{b:x}")); + // But they are not equal. + assert_ne!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs new file mode 100644 index 0000000000000..1e663a13174e2 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs @@ -0,0 +1,25 @@ +//@ run-pass +//@ known-bug: #107975 + +fn main() { + let a: usize = { + let v = 0u8; + &v as *const _ as usize + }; + let b: usize = { + let v = 0u8; + &v as *const _ as usize + }; + + // So, are `a` and `b` equal? + + // Let's check their difference. + let i: usize = a - b; + // It's not zero, which means `a` and `b` are not equal. + assert_ne!(i, 0); + // But it looks like zero... + assert_eq!(i.to_string(), "0"); + // ...and now it *is* zero? + assert_eq!(i, 0); + // So `a` and `b` are equal after all? +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/format.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/format.rs new file mode 100644 index 0000000000000..56702e5149586 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/format.rs @@ -0,0 +1,28 @@ +//@ run-pass +//@ known-bug: #107975 + +#![feature(exposed_provenance)] + +use std::ptr::addr_of; + +fn main() { + let a: usize = { + let v = 0u8; + addr_of!(v).expose_provenance() + }; + let b: usize = { + let v = 0u8; + addr_of!(v).expose_provenance() + }; + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // But they are not equal. + assert_ne!(a, b); + // But they are the same hex number. + assert_eq!(format!("{a:x}"), format!("{b:x}")); + // But they are not equal. + assert_ne!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs new file mode 100644 index 0000000000000..3a48db59f2863 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs @@ -0,0 +1,30 @@ +//@ run-pass +//@ known-bug: #107975 + +#![feature(exposed_provenance)] + +use std::ptr::addr_of; + +fn main() { + let a: usize = { + let v = 0u8; + addr_of!(v).expose_provenance() + }; + let b: usize = { + let v = 0u8; + addr_of!(v).expose_provenance() + }; + + // So, are `a` and `b` equal? + + // Let's check their difference. + let i: usize = a - b; + // It's not zero, which means `a` and `b` are not equal. + assert_ne!(i, 0); + // But it looks like zero... + assert_eq!(i.to_string(), "0"); + // ...and now it *is* zero? + assert_eq!(i, 0); + // So `a` and `b` are equal after all? +} + diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/format.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/format.rs new file mode 100644 index 0000000000000..b622866cedba5 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/format.rs @@ -0,0 +1,28 @@ +//@ run-pass +//@ known-bug: #107975 + +#![feature(strict_provenance)] + +use std::ptr::addr_of; + +fn main() { + let a: usize = { + let v = 0u8; + addr_of!(v).addr() + }; + let b: usize = { + let v = 0u8; + addr_of!(v).addr() + }; + + // `a` and `b` are not equal. + assert_ne!(a, b); + // But they are the same number. + assert_eq!(format!("{a}"), format!("{b}")); + // But they are not equal. + assert_ne!(a, b); + // But they are the same hex number. + assert_eq!(format!("{a:x}"), format!("{b:x}")); + // But they are not equal. + assert_ne!(a, b); +} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs new file mode 100644 index 0000000000000..2d2b5b04636a4 --- /dev/null +++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs @@ -0,0 +1,29 @@ +//@ run-pass +//@ known-bug: #107975 + +#![feature(strict_provenance)] + +use std::ptr::addr_of; + +fn main() { + let a: usize = { + let v = 0u8; + addr_of!(v).addr() + }; + let b: usize = { + let v = 0u8; + addr_of!(v).addr() + }; + + // So, are `a` and `b` equal? + + // Let's check their difference. + let i: usize = a - b; + // It's not zero, which means `a` and `b` are not equal. + assert_ne!(i, 0); + // But it looks like zero... + assert_eq!(i.to_string(), "0"); + // ...and now it *is* zero? + assert_eq!(i, 0); + // So `a` and `b` are equal after all? +}