Unrolled build for #156832
Rollup merge of #156832 - hanna-kruppe:consistent-strict-provenance-lints, r=jhpratt

library: use strict provenance lints consistently

The `fuzzy_provenance_casts` lint is enabled in most of the standard library, but its identical twin `lossy_provenance_casts` was not. As discussed in the tracking issue for those lints, there doesn't seem to be any good reason to enable one without the other. This PR applies this principle and as a result removes some unnecessary ptr->int `as` casts.

It's also preparation for merging the two lints, which removes the option of only enabling `fuzzy_provenance_casts`.

Tracking issue: rust-lang/rust#130351
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 3f0c0ab..f66dc64 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -73,6 +73,7 @@
 // Lints:
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(lossy_provenance_casts)]
 #![warn(deprecated_in_future)]
 #![warn(missing_debug_implementations)]
 #![warn(missing_docs)]
diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs
index b7e09fc2e..2be7a24 100644
--- a/library/alloctests/benches/lib.rs
+++ b/library/alloctests/benches/lib.rs
@@ -7,6 +7,7 @@
 #![feature(strict_provenance_lints)]
 #![feature(test)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(lossy_provenance_casts)]
 
 extern crate test;
 
diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs
index a0c3cb5..c73b710 100644
--- a/library/alloctests/tests/boxed.rs
+++ b/library/alloctests/tests/boxed.rs
@@ -47,9 +47,9 @@ fn box_clone_from_ptr_stability() {
     for size in (0..8).map(|i| 2usize.pow(i)) {
         let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
         let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
-        let copy_raw = copy.as_ptr() as usize;
+        let copy_raw = copy.as_ptr();
         copy.clone_from(&control);
-        assert_eq!(copy.as_ptr() as usize, copy_raw);
+        assert_eq!(copy.as_ptr(), copy_raw);
     }
 }
 
diff --git a/library/alloctests/tests/heap.rs b/library/alloctests/tests/heap.rs
index 246b341..8eb5626 100644
--- a/library/alloctests/tests/heap.rs
+++ b/library/alloctests/tests/heap.rs
@@ -25,7 +25,7 @@ fn check_overalign_requests<T: Allocator>(allocator: T) {
                     .collect();
                 for &ptr in &pointers {
                     assert_eq!(
-                        (ptr.as_non_null_ptr().as_ptr() as usize) % align,
+                        ptr.as_non_null_ptr().as_ptr().addr() % align,
                         0,
                         "Got a pointer less aligned than requested"
                     )
diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs
index 1414835..b7c3e39 100644
--- a/library/alloctests/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -44,6 +44,7 @@
 #![feature(ptr_cast_slice)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(lossy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate alloc;
diff --git a/library/alloctests/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs
index 09b7677..ec4c4fa 100644
--- a/library/alloctests/tests/sort/tests.rs
+++ b/library/alloctests/tests/sort/tests.rs
@@ -746,7 +746,7 @@ fn self_cmp<T: Ord + Clone + Debug, S: Sort>(
         pattern_fn(len).into_iter().map(|val| type_into_fn(val)).collect::<Vec<_>>();
 
     let comparison_fn = |a: &T, b: &T| {
-        assert_ne!(a as *const T as usize, b as *const T as usize);
+        assert_ne!(a as *const T, b as *const T);
         a.cmp(b)
     };
 
diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs
index 54bdc4c..ccf9b80 100644
--- a/library/alloctests/tests/vec.rs
+++ b/library/alloctests/tests/vec.rs
@@ -1110,7 +1110,7 @@ fn test_into_iter_zst() {
     struct AlignedZstWithDrop([u64; 0]);
     impl Drop for AlignedZstWithDrop {
         fn drop(&mut self) {
-            let addr = self as *mut _ as usize;
+            let addr = (self as *mut Self).addr();
             assert!(hint::black_box(addr) % align_of::<u64>() == 0);
         }
     }
@@ -1356,10 +1356,10 @@ fn overaligned_allocations() {
     for i in 0..0x1000 {
         v.reserve_exact(i);
         assert!(v[0].0 == 273);
-        assert!(v.as_ptr() as usize & 0xff == 0);
+        assert!(v.as_ptr().addr() & 0xff == 0);
         v.shrink_to_fit();
         assert!(v[0].0 == 273);
-        assert!(v.as_ptr() as usize & 0xff == 0);
+        assert!(v.as_ptr().addr() & 0xff == 0);
     }
 }
 
@@ -2574,7 +2574,7 @@ fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
 
         unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
             if layout.size() == 0 {
-                let addr = ptr.as_ptr() as usize;
+                let addr = ptr.as_ptr().addr();
                 let mut state = self.state.borrow_mut();
                 std::println!("freeing {addr}");
                 assert!(state.0.remove(&addr), "ZST free that wasn't allocated");
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index b16996a..1cdf52d 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -80,6 +80,7 @@
 #![deny(rust_2021_incompatible_or_patterns)]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(lossy_provenance_casts)]
 #![warn(deprecated_in_future)]
 #![warn(missing_debug_implementations)]
 #![warn(missing_docs)]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 5cbbebf..0a7f9b9 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -183,6 +183,7 @@ pub fn addr(self) -> usize {
     /// [`with_exposed_provenance`]: with_exposed_provenance
     #[inline(always)]
     #[stable(feature = "exposed_provenance", since = "1.84.0")]
+    #[expect(lossy_provenance_casts, reason = "this *is* the replacement")]
     pub fn expose_provenance(self) -> usize {
         self.cast::<()>() as usize
     }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index ff2c18d..593011e 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -2618,21 +2618,21 @@ fn cmp(&self, other: &Self) -> Ordering {
 #[stable(feature = "fnptr_impls", since = "1.4.0")]
 impl<F: FnPtr> hash::Hash for F {
     fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
-        state.write_usize(self.addr() as _)
+        state.write_usize(self.addr().addr())
     }
 }
 
 #[stable(feature = "fnptr_impls", since = "1.4.0")]
 impl<F: FnPtr> fmt::Pointer for F {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::pointer_fmt_inner(self.addr() as _, f)
+        fmt::pointer_fmt_inner(self.addr().addr(), f)
     }
 }
 
 #[stable(feature = "fnptr_impls", since = "1.4.0")]
 impl<F: FnPtr> fmt::Debug for F {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::pointer_fmt_inner(self.addr() as _, f)
+        fmt::pointer_fmt_inner(self.addr().addr(), f)
     }
 }
 
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 53ef7f7..4b68d96 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -174,6 +174,7 @@ pub fn addr(self) -> usize {
     /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut
     #[inline(always)]
     #[stable(feature = "exposed_provenance", since = "1.84.0")]
+    #[expect(lossy_provenance_casts, reason = "this *is* the replacement")]
     pub fn expose_provenance(self) -> usize {
         self.cast::<()>() as usize
     }
diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs
index 877017f..4337200 100644
--- a/library/coretests/tests/char.rs
+++ b/library/coretests/tests/char.rs
@@ -318,7 +318,7 @@ fn check(input: char, expect: &[u8]) {
         let mut buf = [0; char::MAX_LEN_UTF8];
         let ptr = buf.as_ptr();
         let s = input.encode_utf8(&mut buf);
-        assert_eq!(s.as_ptr() as usize, ptr as usize);
+        assert_eq!(s.as_ptr(), ptr);
         assert!(str::from_utf8(s.as_bytes()).is_ok());
         assert_eq!(s.as_bytes(), expect);
     }
@@ -335,7 +335,7 @@ fn check(input: char, expect: &[u16]) {
         let mut buf = [0; 2];
         let ptr = buf.as_mut_ptr();
         let b = input.encode_utf16(&mut buf);
-        assert_eq!(b.as_mut_ptr() as usize, ptr as usize);
+        assert_eq!(b.as_mut_ptr(), ptr);
         assert_eq!(b, expect);
     }
 
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 89e8d5d..aa6aa14 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -129,6 +129,7 @@
 // tidy-alphabetical-end
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(lossy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 /// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality.
diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs
index 93f9454..9dbaf66 100644
--- a/library/coretests/tests/ptr.rs
+++ b/library/coretests/tests/ptr.rs
@@ -384,7 +384,7 @@ fn align_offset_stride_one() {
 #[test]
 fn align_offset_various_strides() {
     unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool {
-        let numptr = ptr as usize;
+        let numptr = ptr.addr();
         let mut expected = usize::MAX;
         // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
         for el in 0..align {
diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs
index 2bb62f3..a4db730 100644
--- a/library/coretests/tests/slice.rs
+++ b/library/coretests/tests/slice.rs
@@ -1886,7 +1886,7 @@ fn test_align_to_empty_mid() {
     type Chunk = u32;
     for offset in 0..4 {
         let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::<Chunk>() };
-        assert_eq!(mid.as_ptr() as usize % align_of::<Chunk>(), 0);
+        assert_eq!(mid.as_ptr().addr() % align_of::<Chunk>(), 0);
     }
 }
 
diff --git a/library/coretests/tests/waker.rs b/library/coretests/tests/waker.rs
index 4889b89..be8b07b 100644
--- a/library/coretests/tests/waker.rs
+++ b/library/coretests/tests/waker.rs
@@ -5,16 +5,16 @@
 fn test_waker_getters() {
     let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE);
     let waker = unsafe { Waker::from_raw(raw_waker) };
-    assert_eq!(waker.data() as usize, 42);
+    assert_eq!(waker.data().addr(), 42);
     assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE));
 
     let waker2 = waker.clone();
-    assert_eq!(waker2.data() as usize, 43);
+    assert_eq!(waker2.data().addr(), 43);
     assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE));
 }
 
 static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
-    |data| RawWaker::new(ptr::without_provenance_mut(data as usize + 1), &WAKER_VTABLE),
+    |data| RawWaker::new(ptr::without_provenance_mut(data.addr() + 1), &WAKER_VTABLE),
     |_| {},
     |_| {},
     |_| {},
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 8086cab..addbb40 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -246,6 +246,7 @@
 #![allow(unused_lifetimes)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(lossy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![allow(rustdoc::redundant_explicit_links)]
 #![warn(rustdoc::unescaped_backticks)]
@@ -723,7 +724,13 @@ pub mod arch {
 mod panicking;
 
 #[path = "../../backtrace/src/lib.rs"]
-#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
+#[allow(
+    dead_code,
+    unused_attributes,
+    fuzzy_provenance_casts,
+    lossy_provenance_casts,
+    unsafe_op_in_unsafe_fn
+)]
 mod backtrace_rs;
 
 #[stable(feature = "cfg_select", since = "1.95.0")]
diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs
index 32085e5..efb349b 100644
--- a/library/std/src/os/unix/thread.rs
+++ b/library/std/src/os/unix/thread.rs
@@ -31,10 +31,15 @@ pub trait JoinHandleExt {
 
 #[stable(feature = "thread_extensions", since = "1.9.0")]
 impl<T> JoinHandleExt for JoinHandle<T> {
+    // This is an int2ptr cast on some platforms (e.g., *-musl) where RawPthread
+    // is an integer but libc::pthread_t is a pointer. Exposed provenance is the
+    // safe choice here, but `as` also works when it's int2int or ptr2ptr.
+    #[allow(lossy_provenance_casts)]
     fn as_pthread_t(&self) -> RawPthread {
         self.as_inner().id() as RawPthread
     }
 
+    #[allow(lossy_provenance_casts)] // see above for why
     fn into_pthread_t(self) -> RawPthread {
         self.into_inner().into_id() as RawPthread
     }
diff --git a/library/std/src/sync/mpmc/select.rs b/library/std/src/sync/mpmc/select.rs
index 56a83fe..ff537aa 100644
--- a/library/std/src/sync/mpmc/select.rs
+++ b/library/std/src/sync/mpmc/select.rs
@@ -22,7 +22,7 @@ impl Operation {
     /// and is alive for the entire duration of a blocking operation.
     #[inline]
     pub fn hook<T>(r: &mut T) -> Operation {
-        let val = r as *mut T as usize;
+        let val = (r as *mut T).addr();
         // Make sure that the pointer address doesn't equal the numerical representation of
         // `Selected::{Waiting, Aborted, Disconnected}`.
         assert!(val > 2);
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index c743462..4f645e1 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -25,7 +25,7 @@ fn default() -> Self {
 
 impl fmt::Debug for ZeroToken {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&(self.0 as usize), f)
+        fmt::Debug::fmt(&self.0.addr(), f)
     }
 }
 
diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs
index 6ff94f5..9403059 100644
--- a/library/std/src/sys/args/sgx.rs
+++ b/library/std/src/sys/args/sgx.rs
@@ -1,4 +1,5 @@
-#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
+// FIXME: this module systematically confuses pointers and integers
+#![allow(fuzzy_provenance_casts, lossy_provenance_casts)]
 
 use crate::ffi::OsString;
 use crate::num::NonZero;
diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs
index 09090ec..0c19fcc 100644
--- a/library/std/src/sys/env/sgx.rs
+++ b/library/std/src/sys/env/sgx.rs
@@ -1,4 +1,5 @@
-#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
+// FIXME: this module systematically confuses pointers and integers
+#![allow(fuzzy_provenance_casts, lossy_provenance_casts)]
 
 pub use super::common::Env;
 use crate::collections::HashMap;
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 2b284cc..7b2c8e5 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -3,7 +3,8 @@
 //! This module contains the facade (aka platform-specific) implementations of
 //! OS level functionality for Fortanix SGX.
 #![deny(unsafe_op_in_unsafe_fn)]
-#![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers
+// FIXME: this entire module systematically confuses pointers and integers
+#![allow(fuzzy_provenance_casts, lossy_provenance_casts)]
 
 use crate::io;
 use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
diff --git a/library/std/src/sys/thread_local/key/tests.rs b/library/std/src/sys/thread_local/key/tests.rs
index c7d2c8e..5e5243d 100644
--- a/library/std/src/sys/thread_local/key/tests.rs
+++ b/library/std/src/sys/thread_local/key/tests.rs
@@ -18,8 +18,8 @@ fn smoke() {
         assert!(get(k2).is_null());
         set(k1, ptr::without_provenance_mut(1));
         set(k2, ptr::without_provenance_mut(2));
-        assert_eq!(get(k1) as usize, 1);
-        assert_eq!(get(k2) as usize, 2);
+        assert_eq!(get(k1).addr(), 1);
+        assert_eq!(get(k2).addr(), 2);
     }
 }
 
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index 4b934c0..78b6f7c 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -152,11 +152,11 @@ fn avoid_copying_the_body<F>(spawnfn: F)
 {
     let (tx, rx) = channel();
 
-    let x: Box<_> = Box::new(1);
-    let x_in_parent = (&*x) as *const i32 as usize;
+    let x: Box<i32> = Box::new(1);
+    let x_in_parent = (&raw const *x).addr();
 
     spawnfn(Box::new(move || {
-        let x_in_child = (&*x) as *const i32 as usize;
+        let x_in_child = (&raw const *x).addr();
         tx.send(x_in_child).unwrap();
     }));