about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_apfloat/src/ieee.rs2
-rw-r--r--compiler/rustc_arena/src/lib.rs26
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs6
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/edition_panic.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/rustup.sh2
-rw-r--r--compiler/rustc_codegen_gcc/Readme.md2
-rw-r--r--compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs2
-rwxr-xr-xcompiler/rustc_codegen_gcc/rustup.sh2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs2
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs2
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation/tests.rs2
-rw-r--r--compiler/rustc_errors/src/styled_buffer.rs2
-rw-r--r--compiler/rustc_expand/src/config.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_expand/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/mbe.rs2
-rw-r--r--compiler/rustc_hir/src/definitions.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs4
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs2
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs2
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs10
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/rc.rs5
-rw-r--r--library/alloc/src/slice.rs4
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/alloc/src/vec/into_iter.rs2
-rw-r--r--library/core/src/alloc/layout.rs2
-rw-r--r--library/core/src/fmt/mod.rs6
-rw-r--r--library/core/src/hash/mod.rs4
-rw-r--r--library/core/src/intrinsics.rs6
-rw-r--r--library/core/src/ptr/const_ptr.rs75
-rw-r--r--library/core/src/ptr/mod.rs331
-rw-r--r--library/core/src/ptr/mut_ptr.rs75
-rw-r--r--library/core/src/ptr/non_null.rs6
-rw-r--r--library/core/src/ptr/unique.rs2
-rw-r--r--library/core/src/slice/ascii.rs6
-rw-r--r--library/core/src/slice/iter/macros.rs4
-rw-r--r--library/core/src/slice/sort.rs4
-rw-r--r--library/std/src/backtrace.rs4
-rw-r--r--library/std/src/fs.rs12
-rw-r--r--library/std/src/io/copy.rs10
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs10
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/unix/net/addr.rs4
-rw-r--r--library/std/src/os/windows/io/handle.rs3
-rw-r--r--library/std/src/os/windows/io/socket.rs1
-rw-r--r--library/std/src/path.rs4
-rw-r--r--library/std/src/process.rs26
-rw-r--r--library/std/src/sync/once.rs49
-rw-r--r--library/std/src/sys/unix/memchr.rs6
-rw-r--r--library/std/src/sys/unix/thread.rs48
-rw-r--r--library/std/src/sys/windows/alloc.rs2
-rw-r--r--library/std/src/sys/windows/c.rs2
-rw-r--r--library/std/src/sys/windows/compat.rs2
-rw-r--r--library/std/src/sys/windows/fs.rs11
-rw-r--r--library/std/src/sys/windows/mod.rs4
-rw-r--r--library/std/src/sys/windows/os.rs2
-rw-r--r--library/std/src/sys/windows/thread_parker.rs12
-rw-r--r--library/std/src/sys_common/condvar/check.rs12
-rw-r--r--library/std/src/thread/local.rs6
-rw-r--r--src/bootstrap/CHANGELOG.md2
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/test/ui/impl-trait/xcrate.rs2
-rw-r--r--src/tools/x/src/main.rs4
96 files changed, 728 insertions, 213 deletions
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
index 96277950cfe..3db8adb2a24 100644
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ b/compiler/rustc_apfloat/src/ieee.rs
@@ -461,7 +461,7 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
                 (combined / 10) as u32 as Limb
             });
 
-            // Reduce the sigificand to avoid wasting time dividing 0's.
+            // Reduce the significand to avoid wasting time dividing 0's.
             while sig.last() == Some(&0) {
                 sig.pop();
             }
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 3928d70c0ed..62995dfd2e2 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -18,6 +18,7 @@
 #![feature(decl_macro)]
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
+#![feature(strict_provenance)]
 
 use smallvec::SmallVec;
 
@@ -87,7 +88,7 @@ impl<T> ArenaChunk<T> {
         unsafe {
             if mem::size_of::<T>() == 0 {
                 // A pointer as large as possible for zero-sized elements.
-                !0 as *mut T
+                ptr::invalid_mut(!0)
             } else {
                 self.start().add(self.storage.len())
             }
@@ -199,7 +200,7 @@ impl<T> TypedArena<T> {
         unsafe {
             if mem::size_of::<T>() == 0 {
                 self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
-                let ptr = mem::align_of::<T>() as *mut T;
+                let ptr = ptr::NonNull::<T>::dangling().as_ptr();
                 // Don't drop the object. This `write` is equivalent to `forget`.
                 ptr::write(ptr, object);
                 &mut *ptr
@@ -216,7 +217,9 @@ impl<T> TypedArena<T> {
 
     #[inline]
     fn can_allocate(&self, additional: usize) -> bool {
-        let available_bytes = self.end.get() as usize - self.ptr.get() as usize;
+        // FIXME: this should *likely* use `offset_from`, but more
+        // investigation is needed (including running tests in miri).
+        let available_bytes = self.end.get().addr() - self.ptr.get().addr();
         let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap();
         available_bytes >= additional_bytes
     }
@@ -262,7 +265,9 @@ impl<T> TypedArena<T> {
                 // If a type is `!needs_drop`, we don't need to keep track of how many elements
                 // the chunk stores - the field will be ignored anyway.
                 if mem::needs_drop::<T>() {
-                    let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
+                    // FIXME: this should *likely* use `offset_from`, but more
+                    // investigation is needed (including running tests in miri).
+                    let used_bytes = self.ptr.get().addr() - last_chunk.start().addr();
                     last_chunk.entries = used_bytes / mem::size_of::<T>();
                 }
 
@@ -288,9 +293,9 @@ impl<T> TypedArena<T> {
     // chunks.
     fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk<T>) {
         // Determine how much was filled.
-        let start = last_chunk.start() as usize;
+        let start = last_chunk.start().addr();
         // We obtain the value of the pointer to the first uninitialized element.
-        let end = self.ptr.get() as usize;
+        let end = self.ptr.get().addr();
         // We then calculate the number of elements to be dropped in the last chunk,
         // which is the filled area's length.
         let diff = if mem::size_of::<T>() == 0 {
@@ -299,6 +304,8 @@ impl<T> TypedArena<T> {
             // Recall that `end` was incremented for each allocated value.
             end - start
         } else {
+            // FIXME: this should *likely* use `offset_from`, but more
+            // investigation is needed (including running tests in miri).
             (end - start) / mem::size_of::<T>()
         };
         // Pass that to the `destroy` method.
@@ -395,15 +402,16 @@ impl DroplessArena {
     /// request.
     #[inline]
     fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
-        let start = self.start.get() as usize;
-        let end = self.end.get() as usize;
+        let start = self.start.get().addr();
+        let old_end = self.end.get();
+        let end = old_end.addr();
 
         let align = layout.align();
         let bytes = layout.size();
 
         let new_end = end.checked_sub(bytes)? & !(align - 1);
         if start <= new_end {
-            let new_end = new_end as *mut u8;
+            let new_end = old_end.with_addr(new_end);
             self.end.set(new_end);
             Some(new_end)
         } else {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index abf1bc739a3..d684a0e67e2 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -634,7 +634,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // This can happen when trying to lower the return type `x` in erroneous code like
         //   async fn foo(x: u8) -> x {}
         // In that case, `x` is lowered as a function parameter, and the return type is lowered as
-        // an opaque type as a synthetized HIR owner.
+        // an opaque type as a synthesized HIR owner.
         res.unwrap_or(Res::Err)
     }
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index aba0b6a7463..a7c600fff78 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -622,9 +622,9 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    /// Reject C-varadic type unless the function is foreign,
+    /// Reject C-variadic type unless the function is foreign,
     /// or free and `unsafe extern "C"` semantically.
-    fn check_c_varadic_type(&self, fk: FnKind<'a>) {
+    fn check_c_variadic_type(&self, fk: FnKind<'a>) {
         match (fk.ctxt(), fk.header()) {
             (Some(FnCtxt::Foreign), _) => return,
             (Some(FnCtxt::Free), Some(header)) => match header.ext {
@@ -1504,7 +1504,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         };
         self.check_fn_decl(fk.decl(), self_semantic);
 
-        self.check_c_varadic_type(fk);
+        self.check_c_variadic_type(fk);
 
         // Functions cannot both be `const async`
         if let Some(FnHeader {
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index f0036f09c38..684eba82667 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -407,10 +407,10 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     fn terminator_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
-        teminator: &mir::Terminator<'tcx>,
+        terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
-        if let mir::TerminatorKind::InlineAsm { operands, .. } = &teminator.kind {
+        if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind {
             for op in operands {
                 if let mir::InlineAsmOperand::Out { place: Some(place), .. }
                 | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index de50f907eff..c1c325adb7f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -55,7 +55,7 @@ impl OutlivesSuggestionBuilder {
             | RegionNameSource::NamedFreeRegion(..)
             | RegionNameSource::Static => true,
 
-            // Don't give suggestions for upvars, closure return types, or other unnamable
+            // Don't give suggestions for upvars, closure return types, or other unnameable
             // regions.
             RegionNameSource::SynthesizedFreeEnvRegion(..)
             | RegionNameSource::AnonRegionFromArgument(..)
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 1df7e826343..e63450a1f58 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -176,7 +176,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         // FIXME. We should handle this case better. It
                         // indicates that we have e.g., some region variable
                         // whose value is like `'a+'b` where `'a` and `'b` are
-                        // distinct unrelated univesal regions that are not
+                        // distinct unrelated universal regions that are not
                         // known to outlive one another. It'd be nice to have
                         // some examples where this arises to decide how best
                         // to report it; we could probably handle it by
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 73ced63e4d7..1a789009f06 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -365,7 +365,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
                     // borrow); so don't check if they interfere.
                     //
                     // NOTE: *reservations* do conflict with themselves;
-                    // thus aren't injecting unsoundenss w/ this check.)
+                    // thus aren't injecting unsoundness w/ this check.)
                     (Activation(_, activating), _) if activating == borrow_index => {
                         // Activating a borrow doesn't generate any invalidations, since we
                         // have already taken the reservation
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 58b246ec873..a8fd5bb50a6 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1048,7 +1048,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // borrow); so don't check if they interfere.
                 //
                 // NOTE: *reservations* do conflict with themselves;
-                // thus aren't injecting unsoundenss w/ this check.)
+                // thus aren't injecting unsoundness w/ this check.)
                 (Activation(_, activating), _) if activating == borrow_index => {
                     debug!(
                         "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
@@ -1107,7 +1107,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     );
                     // rust-lang/rust#56254 - This was previously permitted on
                     // the 2018 edition so we emit it as a warning. We buffer
-                    // these sepately so that we only emit a warning if borrow
+                    // these separately so that we only emit a warning if borrow
                     // checking was otherwise successful.
                     this.reservation_warnings
                         .insert(bi, (place_span.0, place_span.1, location, bk, borrow.clone()));
@@ -1588,7 +1588,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) {
         debug!("check_if_reassignment_to_immutable_state({:?})", local);
 
-        // Check if any of the initializiations of `local` have happened yet:
+        // Check if any of the initializations of `local` have happened yet:
         if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
             // And, if so, report an error.
             let init = &self.move_data.inits[init_index];
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 1f81f7dda13..dabf61715ce 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -789,7 +789,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let universe_a = self.scc_universes[scc_a];
 
         // Quick check: if scc_b's declared universe is a subset of
-        // scc_a's declared univese (typically, both are ROOT), then
+        // scc_a's declared universe (typically, both are ROOT), then
         // it cannot contain any problematic universe elements.
         if universe_a.can_name(self.scc_universes[scc_b]) {
             return true;
@@ -1993,7 +1993,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             .iter()
             .find_map(|constraint| {
                 if let ConstraintCategory::Predicate(predicate_span) = constraint.category {
-                    // We currentl'y doesn't store the `DefId` in the `ConstraintCategory`
+                    // We currently do not store the `DefId` in the `ConstraintCategory`
                     // for performances reasons. The error reporting code used by NLL only
                     // uses the span, so this doesn't cause any problems at the moment.
                     Some(ObligationCauseCode::BindingObligation(
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 9d7dcc5379c..7dc292ffb65 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2507,7 +2507,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // we have to solve them here where we instantiate the
             // closure.
             //
-            // Despite the opacity of the previous parapgrah, this is
+            // Despite the opacity of the previous paragraph, this is
             // actually relatively easy to understand in terms of the
             // desugaring. A closure gets desugared to a struct, and
             // these extra requirements are basically like where
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 3c8f8f1854b..7637bf7edc8 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -137,7 +137,7 @@ impl CfgEval<'_, '_> {
         }
 
         // The majority of parsed attribute targets will never need to have early cfg-expansion
-        // run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro inoput).
+        // run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro input).
         // Therefore, we normally do not capture the necessary information about `#[cfg]`
         // and `#[cfg_attr]` attributes during parsing.
         //
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index fd26a376f91..c952fc0a866 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -28,7 +28,7 @@ pub fn expand_deriving_clone(
     // - the item is a union with Copy fields
     //      Unions with generic parameters still can derive Clone because they require Copy
     //      for deriving, Clone alone is not enough.
-    //      Whever Clone is implemented for fields is irrelevant so we don't assert it.
+    //      Wherever Clone is implemented for fields is irrelevant so we don't assert it.
     let bounds;
     let substructure;
     let is_shallow;
diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs
index 518b88dec6a..ea0e768a58f 100644
--- a/compiler/rustc_builtin_macros/src/edition_panic.rs
+++ b/compiler/rustc_builtin_macros/src/edition_panic.rs
@@ -70,7 +70,7 @@ fn expand<'cx>(
 }
 
 pub fn use_panic_2021(mut span: Span) -> bool {
-    // To determine the editon, we check the first span up the expansion
+    // To determine the edition, we check the first span up the expansion
     // stack that does not have #[allow_internal_unstable(edition_panic)].
     // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
     loop {
diff --git a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
index e9876837dd8..d270fec6b71 100644
--- a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -36,7 +36,7 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
 
 trait Trait {
     // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
-    // without unsized_locals), but wrappers arond `Self` currently are not.
+    // without unsized_locals), but wrappers around `Self` currently are not.
     // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
     // fn wrapper(self: Wrapper<Self>) -> i32;
     fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh
index cc34c080886..bc4c06ed7d2 100755
--- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh
@@ -11,7 +11,7 @@ case $1 in
         sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain
         rustup component add rustfmt || true
 
-        echo "=> Uninstalling all old nighlies"
+        echo "=> Uninstalling all old nightlies"
         for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do
             rustup toolchain uninstall "$nightly"
         done
diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md
index 27b30e0fd1b..fe23a267696 100644
--- a/compiler/rustc_codegen_gcc/Readme.md
+++ b/compiler/rustc_codegen_gcc/Readme.md
@@ -12,7 +12,7 @@ A secondary goal is to check if using the gcc backend will provide any run-time
 ## Building
 
 **This requires a patched libgccjit in order to work.
-The patches in [this repostory](https://github.com/antoyo/libgccjit-patches) need to be applied.
+The patches in [this repository](https://github.com/antoyo/libgccjit-patches) need to be applied.
 (Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.)
 You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
 
diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
index ddeb752f93e..3af0ba09e0b 100644
--- a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -37,7 +37,7 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
 
 trait Trait {
     // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
-    // without unsized_locals), but wrappers arond `Self` currently are not.
+    // without unsized_locals), but wrappers around `Self` currently are not.
     // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
     // fn wrapper(self: Wrapper<Self>) -> i32;
     fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh
index 01ce5bb78be..11d39a122f5 100755
--- a/compiler/rustc_codegen_gcc/rustup.sh
+++ b/compiler/rustc_codegen_gcc/rustup.sh
@@ -10,7 +10,7 @@ case $1 in
         rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists
         echo nightly-${TOOLCHAIN} > rust-toolchain
 
-        echo "=> Uninstalling all old nighlies"
+        echo "=> Uninstalling all old nightlies"
         for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do
             rustup toolchain uninstall $nightly
         done
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index b2f46e92ecc..21c7d420b20 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -508,7 +508,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        // TODO(antoyo): posion if not exact.
+        // TODO(antoyo): poison if not exact.
         // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
         // should be the same.
         let typ = a.get_type().to_signed(self);
@@ -1252,7 +1252,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn do_not_inline(&mut self, _llret: RValue<'gcc>) {
-        // FIMXE(bjorn3): implement
+        // FIXME(bjorn3): implement
     }
 
     fn set_span(&mut self, _span: Span) {}
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 5e5b9e7e9b1..edbe7122bdd 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -110,7 +110,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
     /// `const_undef()` returns struct as pointer so that they can later be assigned a value.
     /// As such, this set remembers which of these pointers were returned by this function so that
-    /// they can be deferenced later.
+    /// they can be dereferenced later.
     /// FIXME(antoyo): fix the rustc API to avoid having this hack.
     pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
 }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 08e584a46f3..68a05d95ef7 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -340,7 +340,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn assume(&mut self, value: Self::Value) {
-        // TODO(antoyo): switch to asumme when it exists.
+        // TODO(antoyo): switch to assume when it exists.
         // Or use something like this:
         // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
         self.expect(value, true);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 9fbc33d4b05..2b76bfdb5ec 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -360,7 +360,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         //   feasible. The compiler may be able to get around this, but it may
         //   involve some invasive changes to deal with this.
         //
-        // The flipside of this situation is that whenever you link to a dll and
+        // The flip side of this situation is that whenever you link to a dll and
         // you import a function from it, the import should be tagged with
         // `dllimport`. At this time, however, the compiler does not emit
         // `dllimport` for any declarations other than constants (where it is
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index e9772cd78d7..31bb9ed3185 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -356,7 +356,7 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
     generator_type_di_node: &'ll DIType,
 ) -> SmallVec<&'ll DIType> {
     let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } = generator_type_and_layout.variants else {
-        bug!("This function only supports layouts with direcly encoded tags.")
+        bug!("This function only supports layouts with directly encoded tags.")
     };
 
     let (generator_def_id, generator_substs) = match generator_type_and_layout.ty.kind() {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 7f804ab5e63..10df671baa2 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1113,7 +1113,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                     && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
                         == Some(expected_bytes) =>
             {
-                // Zero-extend iN to the array lengh:
+                // Zero-extend iN to the array length:
                 let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
 
                 // Convert the integer to a byte array
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 9cc06ac0319..dbbbbd5ecc0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -709,7 +709,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         let out = String::from_utf8_lossy(&out);
 
         // Check to see if the link failed with an error message that indicates it
-        // doesn't recognize the -no-pie option. If so, reperform the link step
+        // doesn't recognize the -no-pie option. If so, re-perform the link step
         // without it. This is safe because if the linker doesn't support -no-pie
         // then it should not default to linking executables as pie. Different
         // versions of gcc seem to use different quotes in the error message so
@@ -1049,7 +1049,7 @@ fn escape_string(s: &[u8]) -> String {
 fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
     // On macOS the runtimes are distributed as dylibs which should be linked to
     // both executables and dynamic shared objects. Everywhere else the runtimes
-    // are currently distributed as static liraries which should be linked to
+    // are currently distributed as static libraries which should be linked to
     // executables only.
     let needs_runtime = match crate_type {
         CrateType::Executable => true,
@@ -1850,7 +1850,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // Upstream rust libraries and their nobundle static libraries
     add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
 
-    // Upstream dymamic native libraries linked with `#[link]` attributes at and `-l`
+    // Upstream dynamic native libraries linked with `#[link]` attributes at and `-l`
     // command line options.
     // If -Zlink-native-libraries=false is set, then the assumption is that an
     // external build system already has the native dependencies defined, and it
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 8191d8b5e49..765bd877db1 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -91,7 +91,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
                     if !generics.requires_monomorphization(tcx)
                         // Functions marked with #[inline] are codegened with "internal"
                         // linkage and are not exported unless marked with an extern
-                        // inidicator
+                        // indicator
                         && (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
                             || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator())
                     {
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 25e27f565ea..6cf6be79a86 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(once_cell)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
+#![feature(strict_provenance)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 5f0f50ae2df..5414c619dcb 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
     fn to_raw_string(&self) -> String {
         match *self {
             MonoItem::Fn(instance) => {
-                format!("Fn({:?}, {})", instance.def, instance.substs.as_ptr() as usize)
+                format!("Fn({:?}, {})", instance.def, instance.substs.as_ptr().addr())
             }
             MonoItem::Static(id) => format!("Static({:?})", id),
             MonoItem::GlobalAsm(id) => format!("GlobalAsm({:?})", id),
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 43ab74f4b88..f1acb9e41c4 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -73,7 +73,7 @@ struct IsStaticOrFn;
 
 /// Intern an allocation without looking at its children.
 /// `mode` is the mode of the environment where we found this pointer.
-/// `mutablity` is the mutability of the place to be interned; even if that says
+/// `mutability` is the mutability of the place to be interned; even if that says
 /// `immutable` things might become mutable if `ty` is not frozen.
 /// `ty` can be `None` if there is no potential interior mutability
 /// to account for (e.g. for vtables).
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 871b7578abd..4a235809119 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -1011,7 +1011,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         let src_parts = self.get_ptr_access(src, size, src_align)?;
         let dest_parts = self.get_ptr_access(dest, size * num_copies, dest_align)?; // `Size` multiplication
 
-        // FIXME: we look up both allocations twice here, once ebfore for the `check_ptr_access`
+        // FIXME: we look up both allocations twice here, once before for the `check_ptr_access`
         // and once below to get the underlying `&[mut] Allocation`.
 
         // Source alloc preparations and access hooks.
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index b1784b12c65..5b8d74b4307 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -876,7 +876,7 @@ where
         if src.layout.size != dest.layout.size {
             // FIXME: This should be an assert instead of an error, but if we transmute within an
             // array length computation, `typeck` may not have yet been run and errored out. In fact
-            // most likey we *are* running `typeck` right now. Investigate whether we can bail out
+            // most likely we *are* running `typeck` right now. Investigate whether we can bail out
             // on `typeck_results().has_errors` at all const eval entry points.
             debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
             self.tcx.sess.delay_span_bug(
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 0701e0ded97..4272bfd5d6c 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -39,7 +39,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ///
     /// This is used by [priroda](https://github.com/oli-obk/priroda)
     ///
-    /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3`
+    /// This is marked `#inline(always)` to work around adversarial codegen when `opt-level = 3`
     #[inline(always)]
     pub fn step(&mut self) -> InterpResult<'tcx, bool> {
         if self.stack().is_empty() {
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 57a93ed4d55..d33358499e2 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -329,7 +329,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
                 // Compute callee information using the `instance` returned by
                 // `find_mir_or_eval_fn`.
-                // FIXME: for variadic support, do we have to somehow determine calle's extra_args?
+                // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
                 let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
                 if callee_fn_abi.c_variadic != caller_fn_abi.c_variadic {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 8790baa010c..e203c79030d 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -953,7 +953,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 if callee_is_unstable_unmarked {
                     trace!("callee_is_unstable_unmarked");
                     // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
-                    // `extern` funtions, and these have no way to get marked `const`. So instead we
+                    // `extern` functions, and these have no way to get marked `const`. So instead we
                     // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
                     if self.ccx.is_const_stable_const_fn() || is_intrinsic {
                         self.check_op(ops::FnCallUnstable(callee, None));
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 1e02129855e..9fd94dc334f 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -56,7 +56,7 @@ pub trait Qualif {
     /// Returns `true` if *any* value of the given type could possibly have this `Qualif`.
     ///
     /// This function determines `Qualif`s when we cannot do a value-based analysis. Since qualif
-    /// propagation is context-insenstive, this includes function arguments and values returned
+    /// propagation is context-insensitive, this includes function arguments and values returned
     /// from a call to another function.
     ///
     /// It also determines the `Qualif`s for primitive types.
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
index 2165989b398..60b45856f51 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -45,7 +45,7 @@ pub enum CallKind<'tcx> {
     },
     /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
     FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
-    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
+    /// A call to an operator trait, desugared from operator syntax (e.g. `a << b`)
     Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
     DerefCoercion {
         /// The `Span` of the `Target` associated type
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 31d6a42cf28..e8d81d4b937 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -623,7 +623,7 @@ pub enum NodeIdHashingMode {
 /// result, it needs to include `HashingControls` as part
 /// of the key, to ensure that is does not produce an incorrect
 /// result (for example, using a `Fingerprint` produced while
-/// hashing `Span`s when a `Fingeprint` without `Span`s is
+/// hashing `Span`s when a `Fingerprint` without `Span`s is
 /// being requested)
 #[derive(Clone, Hash, Eq, PartialEq, Debug)]
 pub struct HashingControls {
diff --git a/compiler/rustc_data_structures/src/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs
index f63b1be1ddc..e1f4c7ee073 100644
--- a/compiler/rustc_data_structures/src/transitive_relation/tests.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation/tests.rs
@@ -96,7 +96,7 @@ fn mubs_best_choice2() {
     //
     // mubs(0,3) = [2]
 
-    // Like the precedecing test, but in this case intersection is [2,
+    // Like the preceding test, but in this case intersection is [2,
     // 1], and hence we rely on the first pare down call.
 
     let mut relation = TransitiveRelation::default();
diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs
index e262d95bb70..9abdb5fc97c 100644
--- a/compiler/rustc_errors/src/styled_buffer.rs
+++ b/compiler/rustc_errors/src/styled_buffer.rs
@@ -26,7 +26,7 @@ impl StyledBuffer {
         StyledBuffer { lines: vec![] }
     }
 
-    /// Returns content of `StyledBuffer` splitted by lines and line styles
+    /// Returns content of `StyledBuffer` split by lines and line styles
     pub fn render(&self) -> Vec<Vec<StyledString>> {
         // Tabs are assumed to have been replaced by spaces in calling code.
         debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 762198887cf..fa628cd9ebd 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -414,7 +414,7 @@ impl<'a> StripUnconfigured<'a> {
             };
             trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
         }
-        // We don't really have a good span to use for the syntheized `[]`
+        // We don't really have a good span to use for the synthesized `[]`
         // in `#[attr]`, so just use the span of the `#` token.
         let bracket_group = AttrAnnotatedTokenTree::Delimited(
             DelimSpan::from_single(pound_span),
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index fe4698d09fd..c3f7f4f27e5 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1847,7 +1847,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         if node.is_expr() {
             // The only way that we can end up with a `MacCall` expression statement,
             // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
-            // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
+            // trailing expression in a block (e.g. `fn foo() { my_macro!() }`).
             // Record this information, so that we can report a more specific
             // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
             // See #78991 for an investigation of treating macros in this position
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 14b3f720f83..791ba560607 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -36,7 +36,7 @@ crate mod mbe;
 // HACK(Centril, #64197): These shouldn't really be here.
 // Rather, they should be with their respective modules which are defined in other crates.
 // However, since for now constructing a `ParseSess` sorta requires `config` from this crate,
-// these tests will need to live here in the iterim.
+// these tests will need to live here in the interim.
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs
index 0f7a8a9ed75..c89015b4c6b 100644
--- a/compiler/rustc_expand/src/mbe.rs
+++ b/compiler/rustc_expand/src/mbe.rs
@@ -41,7 +41,7 @@ impl Delimited {
     }
 
     /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. Panics if
-    /// the delimeter is `NoDelim`.
+    /// the delimiter is `NoDelim`.
     fn close_tt(&self) -> &TokenTree {
         let tt = self.all_tts.last().unwrap();
         debug_assert!(matches!(
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 4c93d661fd2..1ff9395c589 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -56,7 +56,7 @@ impl DefPathTable {
             //
             // See the documentation for DefPathHash for more information.
             panic!(
-                "found DefPathHash collsion between {:?} and {:?}. \
+                "found DefPathHash collision between {:?} and {:?}. \
                     Compilation cannot continue.",
                 def_path1, def_path2
             );
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 64ce196e440..19fc77fb74b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1118,7 +1118,7 @@ pub type BinOp = Spanned<BinOpKind>;
 
 #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum UnOp {
-    /// The `*` operator (deferencing).
+    /// The `*` operator (dereferencing).
     Deref,
     /// The `!` operator (logical negation).
     Not,
@@ -1611,7 +1611,7 @@ impl Expr<'_> {
             | ExprKind::Index(base, _)
             | ExprKind::AddrOf(.., base)
             | ExprKind::Cast(base, _) => {
-                // This isn't exactly true for `Index` and all `Unnary`, but we are using this
+                // This isn't exactly true for `Index` and all `Unary`, but we are using this
                 // method exclusively for diagnostics and there's a *cultural* pressure against
                 // them being used only for its side-effects.
                 base.can_have_side_effects()
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 9601a49267f..20ffde90064 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -146,7 +146,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeR
 
 /// Builds the dependency graph.
 ///
-/// This function breates the *staging dep-graph*. When the dep-graph is modified by a query
+/// This function creates the *staging dep-graph*. When the dep-graph is modified by a query
 /// execution, the new dependency information is not kept in memory but directly
 /// output to this file. `save_dep_graph` then finalizes the staging dep-graph
 /// and moves it to the permanent dep-graph path
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 17ff52cefcf..fed6a608e57 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -164,14 +164,14 @@ impl<Tag> Allocation<Tag> {
         let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| {
             // This results in an error that can happen non-deterministically, since the memory
             // available to the compiler can change between runs. Normally queries are always
-            // deterministic. However, we can be non-determinstic here because all uses of const
+            // deterministic. However, we can be non-deterministic here because all uses of const
             // evaluation (including ConstProp!) will make compilation fail (via hard error
             // or ICE) upon encountering a `MemoryExhausted` error.
             if panic_on_fail {
                 panic!("Allocation::uninit called with panic_on_fail had allocation failure")
             }
             ty::tls::with(|tcx| {
-                tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpreation")
+                tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation")
             });
             InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
         })?;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 10d241ee24c..3b3120cf04b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -192,7 +192,7 @@ fn find_capture_matching_projections<'a, 'tcx>(
         is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
     })?;
 
-    // Convert index to be from the presepective of the entire closure_min_captures map
+    // Convert index to be from the perspective of the entire closure_min_captures map
     // instead of just the root variable capture list
     Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture))
 }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 754ae12bbea..9865588cff4 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -304,7 +304,7 @@ impl<'a> Parser<'a> {
                 // this replace range with it, removing the inner attribute from the final
                 // `AttrAnnotatedTokenStream`. Inner attributes are stored in the parsed AST note.
                 // During macro expansion, they are selectively inserted back into the
-                // token stream (the first inner attribute is remoevd each time we invoke the
+                // token stream (the first inner attribute is removed each time we invoke the
                 // corresponding macro).
                 let range = start_pos..end_pos;
                 if let Capturing::Yes = self.capture_state.capturing {
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index f0ec86ca64a..5ee9c339bb7 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -188,7 +188,7 @@ impl<'a> Parser<'a> {
     ///
     /// Note: If your callback consumes an opening delimiter
     /// (including the case where you call `collect_tokens`
-    /// when the current token is an opening delimeter),
+    /// when the current token is an opening delimiter),
     /// you must also consume the corresponding closing delimiter.
     ///
     /// That is, you can consume
@@ -260,7 +260,7 @@ impl<'a> Parser<'a> {
             // We also call `has_cfg_or_cfg_attr` at the beginning of this function,
             // but we only bail out if there's no possibility of inner attributes
             // (!R::SUPPORTS_CUSTOM_INNER_ATTRS)
-            // We only catpure about `#[cfg]` or `#[cfg_attr]` in `capture_cfg`
+            // We only capture about `#[cfg]` or `#[cfg_attr]` in `capture_cfg`
             // mode - during normal parsing, we don't need any special capturing
             // for those attributes, since they're builtin.
             && !(self.capture_cfg && has_cfg_or_cfg_attr(ret.attrs()))
@@ -382,7 +382,7 @@ impl<'a> Parser<'a> {
         if matches!(self.capture_state.capturing, Capturing::No) {
             self.capture_state.replace_ranges.clear();
             // We don't clear `inner_attr_ranges`, as doing so repeatedly
-            // had a measureable performance impact. Most inner attributes that
+            // had a measurable performance impact. Most inner attributes that
             // we insert will get removed - when we drop the parser, we'll free
             // up the memory used by any attributes that we didn't remove from the map.
         }
@@ -418,7 +418,7 @@ fn make_token_stream(
                 stack.push(FrameData { open: span, open_delim: delim, inner: vec![] });
             }
             FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => {
-                // HACK: If we enconter a mismatched `None` delimiter at the top
+                // HACK: If we encounter a mismatched `None` delimiter at the top
                 // level, just ignore it.
                 if matches!(delim, DelimToken::NoDelim)
                     && (stack.len() == 1
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index ee9983ee8b8..36eddf7784b 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -288,7 +288,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
         let tcx = infcx.tcx;
 
-        // Don't try to proess any nested obligations involving predicates
+        // Don't try to process any nested obligations involving predicates
         // that are already in the `ParamEnv` (modulo regions): we already
         // know that they must hold.
         for predicate in param_env.caller_bounds() {
@@ -683,12 +683,12 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                         && is_new_pred
                     {
                         debug!(
-                            "evaluate_nested_obligations: adding projection predicate\
+                            "evaluate_nested_obligations: adding projection predicate \
                             to computed_preds: {:?}",
                             predicate
                         );
 
-                        // Under unusual circumstances, we can end up with a self-refeential
+                        // Under unusual circumstances, we can end up with a self-referential
                         // projection predicate. For example:
                         // <T as MyType>::Value == <T as MyType>::Value
                         // Not only is displaying this to the user pointless,
@@ -767,7 +767,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                             // We only care about sub-obligations
                             // when we started out trying to unify
                             // some inference variables. See the comment above
-                            // for more infomration
+                            // for more information
                             if p.term().skip_binder().has_infer_types() {
                                 if !self.evaluate_nested_obligations(
                                     ty,
@@ -784,7 +784,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                         }
                         Ok(Ok(None)) => {
                             // It's ok not to make progress when have no inference variables -
-                            // in that case, we were only performing unifcation to check if an
+                            // in that case, we were only performing unification to check if an
                             // error occurred (which would indicate that it's impossible for our
                             // type to implement the auto trait).
                             // However, we should always make progress (either by generating
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 0a180b83355..065d071a2e3 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -127,6 +127,7 @@
 #![feature(slice_ptr_len)]
 #![feature(slice_range)]
 #![feature(str_internals)]
+#![feature(strict_provenance)]
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
 #![feature(try_trait_v2)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 3ddc9acb2e7..0b57c36247e 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2115,13 +2115,12 @@ impl<T> Weak<T> {
     #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
     #[must_use]
     pub const fn new() -> Weak<T> {
-        Weak { ptr: unsafe { NonNull::new_unchecked(usize::MAX as *mut RcBox<T>) } }
+        Weak { ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<RcBox<T>>(usize::MAX)) } }
     }
 }
 
 pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
-    let address = ptr as *mut () as usize;
-    address == usize::MAX
+    (ptr as *mut ()).addr() == usize::MAX
 }
 
 /// Helper type to allow accessing the reference counts without
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index c61e9d85dd1..89d85146963 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -1056,9 +1056,9 @@ where
 
     impl<T> Drop for MergeHole<T> {
         fn drop(&mut self) {
-            // `T` is not a zero-sized type, so it's okay to divide by its size.
-            let len = (self.end as usize - self.start as usize) / mem::size_of::<T>();
+            // `T` is not a zero-sized type, and these are pointers into a slice's elements.
             unsafe {
+                let len = self.end.offset_from(self.start) as usize;
                 ptr::copy_nonoverlapping(self.start, self.dest, len);
             }
         }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index e2b9890850b..f8b4d46ac10 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1746,7 +1746,7 @@ impl<T> Weak<T> {
     #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
     #[must_use]
     pub const fn new() -> Weak<T> {
-        Weak { ptr: unsafe { NonNull::new_unchecked(usize::MAX as *mut ArcInner<T>) } }
+        Weak { ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<ArcInner<T>>(usize::MAX)) } }
     }
 }
 
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index f17b8d71b3a..cc6dfb0e330 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -159,7 +159,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         let exact = if mem::size_of::<T>() == 0 {
-            (self.end as usize).wrapping_sub(self.ptr as usize)
+            self.end.addr().wrapping_sub(self.ptr.addr())
         } else {
             unsafe { self.end.offset_from(self.ptr) as usize }
         };
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index ea639268652..0639d6eed62 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -194,7 +194,7 @@ impl Layout {
     #[inline]
     pub const fn dangling(&self) -> NonNull<u8> {
         // SAFETY: align is guaranteed to be non-zero
-        unsafe { NonNull::new_unchecked(self.align() as *mut u8) }
+        unsafe { NonNull::new_unchecked(crate::ptr::invalid_mut::<u8>(self.align())) }
     }
 
     /// Creates a layout describing the record that can hold a value
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 84cf1753f86..6c1d20f36e2 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -352,6 +352,10 @@ impl<'a> ArgumentV1<'a> {
     }
 
     fn as_usize(&self) -> Option<usize> {
+        // We are type punning a bit here: USIZE_MARKER only takes an &usize but
+        // formatter takes an &Opaque. Rust understandably doesn't think we should compare
+        // the function pointers if they don't have the same signature, so we cast to
+        // usizes to tell it that we just want to compare addresses.
         if self.formatter as usize == USIZE_MARKER as usize {
             // SAFETY: The `formatter` field is only set to USIZE_MARKER if
             // the value is a usize, so this is safe
@@ -2246,7 +2250,7 @@ impl<T: ?Sized> Pointer for *const T {
             }
             f.flags |= 1 << (FlagV1::Alternate as u32);
 
-            let ret = LowerHex::fmt(&(ptr as usize), f);
+            let ret = LowerHex::fmt(&(ptr.addr()), f);
 
             f.width = old_width;
             f.flags = old_flags;
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 53de8b42c05..45c9df0c930 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -793,7 +793,7 @@ mod impls {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             let (address, metadata) = self.to_raw_parts();
-            state.write_usize(address as usize);
+            state.write_usize(address.addr());
             metadata.hash(state);
         }
     }
@@ -803,7 +803,7 @@ mod impls {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             let (address, metadata) = self.to_raw_parts();
-            state.write_usize(address as usize);
+            state.write_usize(address.addr());
             metadata.hash(state);
         }
     }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 129402ad23a..8ad4317c145 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1972,15 +1972,15 @@ extern "rust-intrinsic" {
 /// Checks whether `ptr` is properly aligned with respect to
 /// `align_of::<T>()`.
 pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
-    !ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
+    !ptr.is_null() && ptr.addr() % mem::align_of::<T>() == 0
 }
 
 /// Checks whether the regions of memory starting at `src` and `dst` of size
 /// `count * size_of::<T>()` do *not* overlap.
 #[cfg(debug_assertions)]
 pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
-    let src_usize = src as usize;
-    let dst_usize = dst as usize;
+    let src_usize = src.addr();
+    let dst_usize = dst.addr();
     let size = mem::size_of::<T>().checked_mul(count).unwrap();
     let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
     // If the absolute distance between the ptrs is at least as big as the size of the buffer,
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index ab2e6058d2f..209ea5cb043 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -150,6 +150,79 @@ impl<T: ?Sized> *const T {
         bits as Self
     }
 
+    /// Gets the "address" portion of the pointer.
+    ///
+    /// This is equivalent to `self as usize`, which semantically discards
+    /// *provenance* and *address-space* information. To properly restore that information,
+    /// use [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
+    ///
+    /// On most platforms this will produce a value with the same bytes as the original
+    /// pointer, because all the bytes are dedicated to describing the address.
+    /// Platforms which need to store additional information in the pointer may
+    /// perform a change of representation to produce a value containing only the address
+    /// portion of the pointer. What that means is up to the platform to define.
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance experiment,
+    /// see the [module documentation][crate::ptr] for details.
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "strict_provenance", issue = "95228")]
+    pub fn addr(self) -> usize
+    where
+        T: Sized,
+    {
+        // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
+        self as usize
+    }
+
+    /// Creates a new pointer with the given address.
+    ///
+    /// This performs the same operation as an `addr as ptr` cast, but copies
+    /// the *address-space* and *provenance* of `self` to the new pointer.
+    /// This allows us to dynamically preserve and propagate this important
+    /// information in a way that is otherwise impossible with a unary cast.
+    ///
+    /// This is equivalent to using [`wrapping_offset`][pointer::wrapping_offset] to offset
+    /// `self` to the given address, and therefore has all the same capabilities and restrictions.
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance experiment,
+    /// see the [module documentation][crate::ptr] for details.
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "strict_provenance", issue = "95228")]
+    pub fn with_addr(self, addr: usize) -> Self
+    where
+        T: Sized,
+    {
+        // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
+        //
+        // In the mean-time, this operation is defined to be "as if" it was
+        // a wrapping_offset, so we can emulate it as such. This should properly
+        // restore pointer provenance even under today's compiler.
+        let self_addr = self.addr() as isize;
+        let dest_addr = addr as isize;
+        let offset = dest_addr.wrapping_sub(self_addr);
+
+        // This is the canonical desugarring of this operation
+        self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+    }
+
+    /// Creates a new pointer by mapping `self`'s address to a new one.
+    ///
+    /// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details.
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance experiment,
+    /// see the [module documentation][crate::ptr] for details.
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "strict_provenance", issue = "95228")]
+    pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self
+    where
+        T: Sized,
+    {
+        self.with_addr(f(self.addr()))
+    }
+
     /// Decompose a (possibly wide) pointer into its address and metadata components.
     ///
     /// The pointer can be later reconstructed with [`from_raw_parts`].
@@ -1006,7 +1079,7 @@ impl<T> *const [T] {
     /// use std::ptr;
     ///
     /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
-    /// assert_eq!(slice.as_ptr(), 0 as *const i8);
+    /// assert_eq!(slice.as_ptr(), ptr::null());
     /// ```
     #[inline]
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 59b1b4c1367..6a7841d3de6 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -63,12 +63,269 @@
 //! separate allocated object), heap allocations (each allocation created by the global allocator is
 //! a separate allocated object), and `static` variables.
 //!
+//!
+//! # Strict Provenance
+//!
+//! **The following text is non-normative, insufficiently formal, and is an extremely strict
+//! interpretation of provenance. It's ok if your code doesn't strictly conform to it.**
+//!
+//! [Strict Provenance][] is an experimental set of APIs that help tools that try
+//! to validate the memory-safety of your program's execution. Notably this includes [miri][]
+//! and [CHERI][], which can detect when you access out of bounds memory or otherwise violate
+//! Rust's memory model.
+//!
+//! Provenance must exist in some form for any programming
+//! language compiled for modern computer architectures, but specifying a model for provenance
+//! in a way that is useful to both compilers and programmers is an ongoing challenge.
+//! The [Strict Provenance][] experiment seeks to explore the question: *what if we just said you
+//! couldn't do all the nasty operations that make provenance so messy?*
+//!
+//! What APIs would have to be removed? What APIs would have to be added? How much would code
+//! have to change, and is it worse or better now? Would any patterns become truly inexpressible?
+//! Could we carve out special exceptions for those patterns? Should we?
+//!
+//! A secondary goal of this project is to see if we can disamiguate the many functions of
+//! pointer<->integer casts enough for the definition of `usize` to be loosened so that it
+//! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
+//! to conflate these notions). This would potentially make it possible to more efficiently
+//! target platforms where pointers are larger than offsets, such as CHERI and maybe some
+//! segmented architecures.
+//!
+//! ## Provenance
+//!
+//! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.**
+//!
+//! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial
+//! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky"
+//! and the freed memory gets reallocated before your read/write (in fact this is the
+//! worst-case scenario, UAFs would be much less concerning if this didn't happen!).
+//! To rationalize this claim, pointers need to somehow be *more* than just their addresses:
+//! they must have provenance.
+//!
+//! When an allocation is created, that allocation has a unique Original Pointer. For alloc
+//! APIs this is literally the pointer the call returns, and for local variables and statics,
+//! this is the name of the variable/static. This is mildly overloading the term "pointer"
+//! for the sake of brevity/exposition.
+//!
+//! The Original Pointer for an allocation is guaranteed to have unique access to the entire
+//! allocation and *only* that allocation. In this sense, an allocation can be thought of
+//! as a "sandbox" that cannot be broken into or out of. *Provenance* is the permission
+//! to access an allocation's sandbox and has both a *spatial* and *temporal* component:
+//!
+//! * Spatial: A range of bytes that the pointer is allowed to access.
+//! * Temporal: The lifetime (of the allocation) that access to these bytes is tied to.
+//!
+//! Spatial provenance makes sure you don't go beyond your sandbox, while temporal provenance
+//! makes sure that you can't "get lucky" after your permission to access some memory
+//! has been revoked (either through deallocations or borrows expiring).
+//!
+//! Provenance is implicitly shared with all pointers transitively derived from
+//! The Original Pointer through operations like [`offset`], borrowing, and pointer casts.
+//! Some operations may *shrink* the derived provenance, limiting how much memory it can
+//! access or how long it's valid for (i.e. borrowing a subfield and subslicing).
+//!
+//! Shrinking provenance cannot be undone: even if you "know" there is a larger allocation, you
+//! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine"
+//! two contiguous provenances back into one (i.e. with a `fn merge(&[T], &[T]) -> &[T]`).
+//!
+//! A reference to a value always has provenance over exactly the memory that field occupies.
+//! A reference to a slice always has provenance over exactly the range that slice describes.
+//!
+//! If an allocation is deallocated, all pointers with provenance to that allocation become
+//! invalidated, and effectively lose their provenance.
+//!
+//! The strict provenance experiment is mostly only interested in exploring stricter *spatial*
+//! provenance. In this sense it can be thought of as a subset of the more ambitious and
+//! formal [Stacked Borrows][] research project, which is what tools like [miri][] are based on.
+//! In particular, Stacked Borrows is necessary to properly describe what borrows are allowed
+//! to do and when they become invalidated. This necessarily involves much more complex
+//! *temporal* reasoning than simply identifying allocations. Adjusting APIs and code
+//! for the strict provenance experiment will also greatly help Stacked Borrows.
+//!
+//!
+//! ## Pointer Vs Addresses
+//!
+//! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.**
+//!
+//! One of the largest historical issues with trying to define provenance is that programmers
+//! freely convert between pointers and integers. Once you allow for this, it generally becomes
+//! impossible to accurately track and preserve provenance information, and you need to appeal
+//! to very complex and unreliable heuristics. But of course, converting between pointers and
+//! integers is very useful, so what can we do?
+//!
+//! Also did you know WASM is actually a "Harvard Architecture"? As in function pointers are
+//! handled completely differently from data pointers? And we kind of just shipped Rust on WASM
+//! without really addressing the fact that we let you freely convert between function pointers
+//! and data pointers, because it mostly Just Works? Let's just put that on the "pointer casts
+//! are dubious" pile.
+//!
+//! Strict Provenance attempts to square these circles by decoupling Rust's traditional conflation
+//! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the
+//! following information:
+//!
+//! * The **address-space** it is part of (i.e. "data" vs "code" in WASM).
+//! * The **address** it points to, which can be represented by a `usize`.
+//! * The **provenance** it has, defining the memory it has permission to access.
+//!
+//! Under Strict Provenance, a usize *cannot* accurately represent a pointer, and converting from
+//! a pointer to a usize is generally an operation which *only* extracts the address. It is
+//! therefore *impossible* to construct a valid pointer from a usize because there is no way
+//! to restore the address-space and provenance.
+//!
+//! The key insight to making this model *at all* viable is the [`with_addr`][] method:
+//!
+//! ```text
+//!     /// Creates a new pointer with the given address.
+//!     ///
+//!     /// This performs the same operation as an `addr as ptr` cast, but copies
+//!     /// the *address-space* and *provenance* of `self` to the new pointer.
+//!     /// This allows us to dynamically preserve and propagate this important
+//!     /// information in a way that is otherwise impossible with a unary cast.
+//!     ///
+//!     /// This is equivalent to using `wrapping_offset` to offset `self` to the
+//!     /// given address, and therefore has all the same capabilities and restrictions.
+//!     pub fn with_addr(self, addr: usize) -> Self;
+//! ```
+//!
+//! So you're still able to drop down to the address representation and do whatever
+//! clever bit tricks you want *as long as* you're able to keep around a pointer
+//! into the allocation you care about that can "reconstitute" the other parts of the pointer.
+//! Usually this is very easy, because you only are taking a pointer, messing with the address,
+//! and then immediately converting back to a pointer. To make this use case more ergonomic,
+//! we provide the [`map_addr`][] method.
+//!
+//! To help make it clear that code is "following" Strict Provenance semantics, we also
+//! provide an [`addr`][] method which is currently equivalent to `ptr as usize`. In the
+//! future we may provide a lint for pointer<->integer casts to help you audit if your
+//! code conforms to strict provenance.
+//!
+//!
+//! ## Using Strict Provenance
+//!
+//! Most code needs no changes to conform to strict provenance, as the only really concerning
+//! operation that *wasn't* obviously already Undefined Behaviour is casts from usize to a
+//! pointer. For code which *does* cast a usize to a pointer, the scope of the change depends
+//! on exactly what you're doing.
+//!
+//! In general you just need to make sure that if you want to convert a usize address to a
+//! pointer and then use that pointer to read/write memory, you need to keep around a pointer
+//! that has sufficient provenance to perform that read/write itself. In this way all of your
+//! casts from an address to a pointer are essentially just applying offsets/indexing.
+//!
+//! This is generally trivial to do for simple cases like tagged pointers *as long as you
+//! represent the tagged pointer as an actual pointer and not a usize*. For instance:
+//!
+//! ```
+//! #![feature(strict_provenance)]
+//!
+//! unsafe {
+//!     // A flag we want to pack into our pointer
+//!     static HAS_DATA: usize = 0x1;
+//!     static FLAG_MASK: usize = !HAS_DATA;
+//!
+//!     // Our value, which must have enough alignment to have spare least-significant-bits.
+//!     let my_precious_data: u32 = 17;
+//!     assert!(core::mem::align_of::<u32>() > 1);
+//!
+//!     // Create a tagged pointer
+//!     let ptr = &my_precious_data as *const u32;
+//!     let tagged = ptr.map_addr(|addr| addr | HAS_DATA);
+//!
+//!     // Check the flag:
+//!     if tagged.addr() & HAS_DATA != 0 {
+//!         // Untag and read the pointer
+//!         let data = *tagged.map_addr(|addr| addr & FLAG_MASK);
+//!         assert_eq!(data, 17);
+//!     } else {
+//!         unreachable!()
+//!     }
+//! }
+//! ```
+//!
+//! (Yes, if you've been using AtomicUsize for pointers in concurrent datastructures, you should
+//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
+//! we would like to know why, and what needs to be done to fix it.)
+//!
+//! Something more complicated and just generally *evil* like a XOR-List requires more significant
+//! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer
+//! to the whole allocation to reconstitute the XORed addresses.
+//!
+//! Situations where a valid pointer *must* be created from just an address, such as baremetal code
+//! accessing a memory-mapped interface at a fixed address, are an open question on how to support.
+//! These situations *will* still be allowed, but we might require some kind of "I know what I'm
+//! doing" annotation to explain the situation to the compiler. It's also possible they need no
+//! special attention at all, because they're generally accessing memory outside the scope of
+//! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile".
+//!
+//! Under [Strict Provenance] is is Undefined Behaviour to:
+//!
+//! * Access memory through a pointer that does not have provenance over that memory.
+//!
+//! * [`offset`] a pointer to or from an address it doesn't have provenance over.
+//!   This means it's always UB to offset a pointer derived from something deallocated,
+//!   even if the offset is 0. Note that a pointer "one past the end" of its provenance
+//!   is not actually outside its provenance, it just has 0 bytes it can load/store.
+//!
+//! But it *is* still sound to:
+//!
+//! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can
+//!   be used for sentinel values like `null` *or* to represent a tagged pointer that will
+//!   never be dereferencable. In general, it is always sound for an integer to pretend
+//!   to be a pointer "for fun" as long as you don't use operations on it which require
+//!   it to be valid (offset, read, write, etc).
+//!
+//! * Forge an allocation of size zero at any sufficiently aligned non-null address.
+//!   i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies
+//!   for actual forgery (integers cast to pointers). If you borrow some struct's field
+//!   that *happens* to be zero-sized, the resulting pointer will have provenance tied to
+//!   that allocation and it will still get invalidated if the allocation gets deallocated.
+//!   In the future we may introduce an API to make such a forged allocation explicit.
+//!
+//! * [`wrapping_offset`][] a pointer outside its provenance. This includes invalid pointers
+//!   which have "no" provenance. Unfortunately there may be practical limits on this for a
+//!   particular platform, and it's an open question as to how to specify this (if at all).
+//!   Notably, [CHERI][] relies on a compression scheme that can't handle a
+//!   pointer getting offset "too far" out of bounds. If this happens, the address
+//!   returned by `addr` will be the value you expect, but the provenance will get invalidated
+//!   and using it to read/write will fault. The details of this are architecture-specific
+//!   and based on alignment, but the buffer on either side of the pointer's range is pretty
+//!   generous (think kilobytes, not bytes).
+//!
+//! * Compare arbitrary pointers by address. Addresses *are* just integers and so there is
+//!   always a coherent answer, even if the pointers are invalid or from different
+//!   address-spaces/provenances. Of course, comparing addresses from different address-spaces
+//!   is generally going to be *meaningless*, but so is comparing Kilograms to Meters, and Rust
+//!   doesn't prevent that either. Similarly, if you get "lucky" and notice that a pointer
+//!   one-past-the-end is the "same" address as the start of an unrelated allocation, anything
+//!   you do with that fact is *probably* going to be gibberish. The scope of that gibberish
+//!   is kept under control by the fact that the two pointers *still* aren't allowed to access
+//!   the other's allocation (bytes), because they still have different provenance.
+//!
+//! * Perform pointer tagging tricks. This falls out of [`wrapping_offset`] but is worth
+//!   mentioning in more detail because of the limitations of [CHERI][]. Low-bit tagging
+//!   is very robust, and often doesn't even go out of bounds because types ensure
+//!   size >= align (and over-aligning actually gives CHERI more flexibility). Anything
+//!   more complex than this rapidly enters "extremely platform-specific" territory as
+//!   certain things may or may not be allowed based on specific supported operations.
+//!   For instance, ARM explicitly supports high-bit tagging, and so CHERI on ARM inherits
+//!   that and should support it.
+//!
+//!
 //! [aliasing]: ../../nomicon/aliasing.html
 //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
 //! [ub]: ../../reference/behavior-considered-undefined.html
 //! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts
 //! [atomic operations]: crate::sync::atomic
 //! [`offset`]: pointer::offset
+//! [`wrapping_offset`]: pointer::wrapping_offset
+//! [`with_addr`]: pointer::with_addr
+//! [`map_addr`]: pointer::map_addr
+//! [`addr`]: pointer::addr
+//! [`ptr::invalid`]: core::ptr::invalid
+//! [miri]: https://github.com/rust-lang/miri
+//! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
+//! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228
+//! [Stacked Borrows]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -210,7 +467,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
 #[rustc_diagnostic_item = "ptr_null"]
 pub const fn null<T>() -> *const T {
-    0 as *const T
+    invalid(0)
 }
 
 /// Creates a null mutable raw pointer.
@@ -230,7 +487,61 @@ pub const fn null<T>() -> *const T {
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
 #[rustc_diagnostic_item = "ptr_null_mut"]
 pub const fn null_mut<T>() -> *mut T {
-    0 as *mut T
+    invalid_mut(0)
+}
+
+/// Creates an invalid pointer with the given address.
+///
+/// This is *currently* equivalent to `addr as *const T` but it expresses the intended semantic
+/// more clearly, and may become important under future memory models.
+///
+/// The module's top-level documentation discusses the precise meaning of an "invalid"
+/// pointer but essentially this expresses that the pointer is not associated
+/// with any actual allocation and is little more than a usize address in disguise.
+///
+/// This pointer will have no provenance associated with it and is therefore
+/// UB to read/write/offset. This mostly exists to facilitate things
+/// like ptr::null and NonNull::dangling which make invalid pointers.
+///
+/// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it
+/// may be desirable to give them their own API just to make that 100% clear.)
+///
+/// This API and its claimed semantics are part of the Strict Provenance experiment,
+/// see the [module documentation][crate::ptr] for details.
+#[inline(always)]
+#[must_use]
+#[rustc_const_stable(feature = "strict_provenance", since = "1.61.0")]
+#[unstable(feature = "strict_provenance", issue = "95228")]
+pub const fn invalid<T>(addr: usize) -> *const T {
+    // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
+    addr as *const T
+}
+
+/// Creates an invalid mutable pointer with the given address.
+///
+/// This is *currently* equivalent to `addr as *mut T` but it expresses the intended semantic
+/// more clearly, and may become important under future memory models.
+///
+/// The module's top-level documentation discusses the precise meaning of an "invalid"
+/// pointer but essentially this expresses that the pointer is not associated
+/// with any actual allocation and is little more than a usize address in disguise.
+///
+/// This pointer will have no provenance associated with it and is therefore
+/// UB to read/write/offset. This mostly exists to facilitate things
+/// like ptr::null and NonNull::dangling which make invalid pointers.
+///
+/// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it
+/// may be desirable to give them their own API just to make that 100% clear.)
+///
+/// This API and its claimed semantics are part of the Strict Provenance experiment,
+/// see the [module documentation][crate::ptr] for details.
+#[inline(always)]
+#[must_use]
+#[rustc_const_stable(feature = "strict_provenance", since = "1.61.0")]
+#[unstable(feature = "strict_provenance", issue = "95228")]
+pub const fn invalid_mut<T>(addr: usize) -> *mut T {
+    // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
+    addr as *mut T
 }
 
 /// Forms a raw slice from a pointer and a length.
@@ -1110,6 +1421,8 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
         unchecked_shl, unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
     };
 
+    let addr = p.addr();
+
     /// Calculate multiplicative modular inverse of `x` modulo `m`.
     ///
     /// This implementation is tailored for `align_offset` and has following preconditions:
@@ -1170,13 +1483,10 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
         //
         // which distributes operations around the load-bearing, but pessimizing `and` sufficiently
         // for LLVM to be able to utilize the various optimizations it knows about.
-        return wrapping_sub(
-            wrapping_add(p as usize, a_minus_one) & wrapping_sub(0, a),
-            p as usize,
-        );
+        return wrapping_sub(wrapping_add(addr, a_minus_one) & wrapping_sub(0, a), addr);
     }
 
-    let pmoda = p as usize & a_minus_one;
+    let pmoda = addr & a_minus_one;
     if pmoda == 0 {
         // Already aligned. Yay!
         return 0;
@@ -1193,7 +1503,7 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
     let gcd = unsafe { unchecked_shl(1usize, gcdpow) };
 
     // SAFETY: gcd is always greater or equal to 1.
-    if p as usize & unsafe { unchecked_sub(gcd, 1) } == 0 {
+    if addr & unsafe { unchecked_sub(gcd, 1) } == 0 {
         // This branch solves for the following linear congruence equation:
         //
         // ` p + so = 0 mod a `
@@ -1347,6 +1657,11 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
     hashee.hash(into);
 }
 
+// FIXME(strict_provenance_magic): function pointers have buggy codegen that
+// necessitates casting to a usize to get the backend to do the right thing.
+// for now I will break AVR to silence *a billion* lints. We should probably
+// have a proper "opaque function pointer type" to handle this kind of thing.
+
 // Impls for function pointers
 macro_rules! fnptr_impls_safety_abi {
     ($FnTy: ty, $($Arg: ident),*) => {
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 6a71815c3cf..bfc89625935 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -154,6 +154,79 @@ impl<T: ?Sized> *mut T {
         bits as Self
     }
 
+    /// Gets the "address" portion of the pointer.
+    ///
+    /// This is equivalent to `self as usize`, which semantically discards
+    /// *provenance* and *address-space* information. To properly restore that information,
+    /// use [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
+    ///
+    /// On most platforms this will produce a value with the same bytes as the original
+    /// pointer, because all the bytes are dedicated to describing the address.
+    /// Platforms which need to store additional information in the pointer may
+    /// perform a change of representation to produce a value containing only the address
+    /// portion of the pointer. What that means is up to the platform to define.
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance experiment,
+    /// see the [module documentation][crate::ptr] for details.
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "strict_provenance", issue = "95228")]
+    pub fn addr(self) -> usize
+    where
+        T: Sized,
+    {
+        // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
+        self as usize
+    }
+
+    /// Creates a new pointer with the given address.
+    ///
+    /// This performs the same operation as an `addr as ptr` cast, but copies
+    /// the *address-space* and *provenance* of `self` to the new pointer.
+    /// This allows us to dynamically preserve and propagate this important
+    /// information in a way that is otherwise impossible with a unary cast.
+    ///
+    /// This is equivalent to using [`wrapping_offset`][pointer::wrapping_offset] to offset
+    /// `self` to the given address, and therefore has all the same capabilities and restrictions.
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance experiment,
+    /// see the [module documentation][crate::ptr] for details.
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "strict_provenance", issue = "95228")]
+    pub fn with_addr(self, addr: usize) -> Self
+    where
+        T: Sized,
+    {
+        // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
+        //
+        // In the mean-time, this operation is defined to be "as if" it was
+        // a wrapping_offset, so we can emulate it as such. This should properly
+        // restore pointer provenance even under today's compiler.
+        let self_addr = self.addr() as isize;
+        let dest_addr = addr as isize;
+        let offset = dest_addr.wrapping_sub(self_addr);
+
+        // This is the canonical desugarring of this operation
+        self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+    }
+
+    /// Creates a new pointer by mapping `self`'s address to a new one.
+    ///
+    /// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details.
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance experiment,
+    /// see the [module documentation][crate::ptr] for details.
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "strict_provenance", issue = "95228")]
+    pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self
+    where
+        T: Sized,
+    {
+        self.with_addr(f(self.addr()))
+    }
+
     /// Decompose a (possibly wide) pointer into its address and metadata components.
     ///
     /// The pointer can be later reconstructed with [`from_raw_parts_mut`].
@@ -1276,7 +1349,7 @@ impl<T> *mut [T] {
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
-    /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8);
+    /// assert_eq!(slice.as_mut_ptr(), ptr::null_mut());
     /// ```
     #[inline(always)]
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index a698aec51ca..c1b19895f00 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -90,7 +90,7 @@ impl<T: Sized> NonNull<T> {
         // to a *mut T. Therefore, `ptr` is not null and the conditions for
         // calling new_unchecked() are respected.
         unsafe {
-            let ptr = mem::align_of::<T>() as *mut T;
+            let ptr = crate::ptr::invalid_mut::<T>(mem::align_of::<T>());
             NonNull::new_unchecked(ptr)
         }
     }
@@ -469,7 +469,7 @@ impl<T> NonNull<[T]> {
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
-    /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
+    /// assert_eq!(slice.as_non_null_ptr(), NonNull::<i8>::dangling());
     /// ```
     #[inline]
     #[must_use]
@@ -489,7 +489,7 @@ impl<T> NonNull<[T]> {
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
-    /// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8);
+    /// assert_eq!(slice.as_mut_ptr(), NonNull::<i8>::dangling().as_ptr());
     /// ```
     #[inline]
     #[must_use]
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index cff68f64f78..29398cbeb23 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -73,7 +73,7 @@ impl<T: Sized> Unique<T> {
     pub const fn dangling() -> Self {
         // SAFETY: mem::align_of() returns a valid, non-null pointer. The
         // conditions to call new_unchecked() are thus respected.
-        unsafe { Unique::new_unchecked(mem::align_of::<T>() as *mut T) }
+        unsafe { Unique::new_unchecked(crate::ptr::invalid_mut::<T>(mem::align_of::<T>())) }
     }
 }
 
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 1825ccda479..7c002130040 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -294,7 +294,7 @@ fn is_ascii(s: &[u8]) -> bool {
     // Paranoia check about alignment, since we're about to do a bunch of
     // unaligned loads. In practice this should be impossible barring a bug in
     // `align_offset` though.
-    debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);
+    debug_assert_eq!(word_ptr.addr() % mem::align_of::<usize>(), 0);
 
     // Read subsequent words until the last aligned word, excluding the last
     // aligned word by itself to be done in tail check later, to ensure that
@@ -302,9 +302,9 @@ fn is_ascii(s: &[u8]) -> bool {
     while byte_pos < len - USIZE_SIZE {
         debug_assert!(
             // Sanity check that the read is in bounds
-            (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
+            (word_ptr.addr() + USIZE_SIZE) <= start.addr().wrapping_add(len) &&
             // And that our assumptions about `byte_pos` hold.
-            (word_ptr as usize) - (start as usize) == byte_pos
+            (word_ptr.addr() - start.addr()) == byte_pos
         );
 
         // SAFETY: We know `word_ptr` is properly aligned (because of
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index cf15756868e..b74ab28fc09 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -20,13 +20,13 @@ macro_rules! len {
         if size == 0 {
             // This _cannot_ use `unchecked_sub` because we depend on wrapping
             // to represent the length of long ZST slice iterators.
-            ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
+            $self.end.addr().wrapping_sub(start.as_ptr().addr())
         } else {
             // We know that `start <= end`, so can do better than `offset_from`,
             // which needs to deal in signed.  By setting appropriate flags here
             // we can tell LLVM this, which helps it remove bounds checks.
             // SAFETY: By the type invariant, `start <= end`
-            let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
+            let diff = unsafe { unchecked_sub($self.end.addr(), start.as_ptr().addr()) };
             // By also telling LLVM that the pointers are apart by an exact
             // multiple of the type size, it can optimize `len() == 0` down to
             // `start == end` instead of `(end - start) < size`.
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 2ba0e5320d7..1f392a07971 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -269,7 +269,9 @@ where
     // Returns the number of elements between pointers `l` (inclusive) and `r` (exclusive).
     fn width<T>(l: *mut T, r: *mut T) -> usize {
         assert!(mem::size_of::<T>() > 0);
-        (r as usize - l as usize) / mem::size_of::<T>()
+        // FIXME: this should *likely* use `offset_from`, but more
+        // investigation is needed (including running tests in miri).
+        (r.addr() - l.addr()) / mem::size_of::<T>()
     }
 
     loop {
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 94e6070c0f7..05e9b2eb6bc 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -330,7 +330,7 @@ impl Backtrace {
                     frame: RawFrame::Actual(frame.clone()),
                     symbols: Vec::new(),
                 });
-                if frame.symbol_address() as usize == ip && actual_start.is_none() {
+                if frame.symbol_address().addr() == ip && actual_start.is_none() {
                     actual_start = Some(frames.len());
                 }
                 true
@@ -493,7 +493,7 @@ impl RawFrame {
         match self {
             RawFrame::Actual(frame) => frame.ip(),
             #[cfg(test)]
-            RawFrame::Fake => 1 as *mut c_void,
+            RawFrame::Fake => crate::ptr::invalid_mut(1),
         }
     }
 }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index d4e103ab525..46acd0ee4c5 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1729,11 +1729,17 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 /// This function currently corresponds to the `open` function in Unix
 /// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
 /// `O_CLOEXEC` is set for returned file descriptors.
+///
+/// On Linux (including Android), this function attempts to use `copy_file_range(2)`,
+/// and falls back to reading and writing if that is not possible.
+///
 /// On Windows, this function currently corresponds to `CopyFileEx`. Alternate
 /// NTFS streams are copied but only the size of the main stream is returned by
-/// this function. On MacOS, this function corresponds to `fclonefileat` and
-/// `fcopyfile`.
-/// Note that, this [may change in the future][changes].
+/// this function.
+///
+/// On MacOS, this function corresponds to `fclonefileat` and `fcopyfile`.
+///
+/// Note that platform-specific behavior [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
 ///
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 6ab96662305..1a10245e4a5 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -39,6 +39,16 @@ use crate::mem::MaybeUninit;
 ///     Ok(())
 /// }
 /// ```
+///
+/// # Platform-specific behavior
+///
+/// On Linux (including Android), this function uses `copy_file_range(2)`,
+/// `sendfile(2)` or `splice(2)` syscalls to move data directly between file
+/// descriptors if possible.
+///
+/// Note that platform-specific behavior [may change in the future][changes].
+///
+/// [changes]: crate::io#platform-specific-behavior
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
 where
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 208d5a80c5a..e80068b46ab 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -106,7 +106,7 @@ use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
 use alloc::boxed::Box;
 use core::marker::PhantomData;
 use core::mem::{align_of, size_of};
-use core::ptr::NonNull;
+use core::ptr::{self, NonNull};
 
 // The 2 least-significant bits are used as tag.
 const TAG_MASK: usize = 0b11;
@@ -136,7 +136,7 @@ impl Repr {
         let p = Box::into_raw(b).cast::<u8>();
         // Should only be possible if an allocator handed out a pointer with
         // wrong alignment.
-        debug_assert_eq!((p as usize & TAG_MASK), 0);
+        debug_assert_eq!(p.addr() & TAG_MASK, 0);
         // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
         // end of file), and both the start and end of the expression must be
         // valid without address space wraparound due to `Box`'s semantics.
@@ -166,7 +166,7 @@ impl Repr {
     pub(super) fn new_os(code: i32) -> Self {
         let utagged = ((code as usize) << 32) | TAG_OS;
         // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
-        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
+        let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
@@ -180,7 +180,7 @@ impl Repr {
     pub(super) fn new_simple(kind: ErrorKind) -> Self {
         let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
         // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
-        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
+        let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
         // quickly smoke-check we encoded the right thing (This generally will
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
@@ -238,7 +238,7 @@ unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
 where
     F: FnOnce(*mut Custom) -> C,
 {
-    let bits = ptr.as_ptr() as usize;
+    let bits = ptr.as_ptr().addr();
     match bits & TAG_MASK {
         TAG_OS => {
             let code = ((bits as i64) >> 32) as i32;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index a464f2d4c74..133ced5f26c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -275,6 +275,7 @@
 #![feature(extend_one)]
 #![feature(float_minimum_maximum)]
 #![feature(format_args_nl)]
+#![feature(strict_provenance)]
 #![feature(get_mut_unchecked)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index a3ef4b2d92c..9aeae4b2cae 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -17,8 +17,8 @@ mod libc {
 
 fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
     // Work with an actual instance of the type since using a null pointer is UB
-    let base = addr as *const _ as usize;
-    let path = &addr.sun_path as *const _ as usize;
+    let base = (addr as *const libc::sockaddr_un).addr();
+    let path = (&addr.sun_path as *const libc::c_char).addr();
     path - base
 }
 
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 120af9f99dd..ee30cc8be6b 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -9,6 +9,7 @@ use crate::fs;
 use crate::io;
 use crate::marker::PhantomData;
 use crate::mem::forget;
+use crate::ptr;
 use crate::sys::c;
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -182,7 +183,7 @@ impl OwnedHandle {
             return unsafe { Ok(Self::from_raw_handle(handle)) };
         }
 
-        let mut ret = 0 as c::HANDLE;
+        let mut ret = ptr::null_mut();
         cvt(unsafe {
             let cur_proc = c::GetCurrentProcess();
             c::DuplicateHandle(
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index a6b979cc22b..db93cd15d4a 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -129,6 +129,7 @@ impl OwnedSocket {
         }
     }
 
+    // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-;
     #[cfg(not(target_vendor = "uwp"))]
     pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
         cvt(unsafe {
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index bcf5c9328b7..8ecea8ce07f 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1449,8 +1449,8 @@ impl PathBuf {
         };
 
         // truncate until right after the file stem
-        let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
-        let start = os_str_as_u8_slice(&self.inner).as_ptr() as usize;
+        let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
+        let start = os_str_as_u8_slice(&self.inner).as_ptr().addr();
         let v = self.as_mut_vec();
         v.truncate(end_file_stem.wrapping_sub(start));
 
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index d3c8d864b0c..771461a5908 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1705,17 +1705,17 @@ impl crate::error::Error for ExitStatusError {}
 /// }
 /// ```
 #[derive(Clone, Copy, Debug)]
-#[stable(feature = "process_exitcode", since = "1.60.0")]
+#[stable(feature = "process_exitcode", since = "1.61.0")]
 pub struct ExitCode(imp::ExitCode);
 
-#[stable(feature = "process_exitcode", since = "1.60.0")]
+#[stable(feature = "process_exitcode", since = "1.61.0")]
 impl ExitCode {
     /// The canonical `ExitCode` for successful termination on this platform.
     ///
     /// Note that a `()`-returning `main` implicitly results in a successful
     /// termination, so there's no need to return this from `main` unless
     /// you're also returning other possible codes.
-    #[stable(feature = "process_exitcode", since = "1.60.0")]
+    #[stable(feature = "process_exitcode", since = "1.61.0")]
     pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS);
 
     /// The canonical `ExitCode` for unsuccessful termination on this platform.
@@ -1723,7 +1723,7 @@ impl ExitCode {
     /// If you're only returning this and `SUCCESS` from `main`, consider
     /// instead returning `Err(_)` and `Ok(())` respectively, which will
     /// return the same codes (but will also `eprintln!` the error).
-    #[stable(feature = "process_exitcode", since = "1.60.0")]
+    #[stable(feature = "process_exitcode", since = "1.61.0")]
     pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
 }
 
@@ -1747,7 +1747,7 @@ impl ExitCode {
     }
 }
 
-#[stable(feature = "process_exitcode", since = "1.60.0")]
+#[stable(feature = "process_exitcode", since = "1.61.0")]
 impl From<u8> for ExitCode {
     /// Construct an `ExitCode` from an arbitrary u8 value.
     fn from(code: u8) -> Self {
@@ -2092,7 +2092,7 @@ pub fn id() -> u32 {
 /// standard library's runtime for convenience. Other runtimes are not required
 /// to provide similar functionality.
 #[cfg_attr(not(test), lang = "termination")]
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 #[rustc_on_unimplemented(
     message = "`main` has invalid return type `{Self}`",
     label = "`main` can only return types that implement `{Termination}`"
@@ -2100,11 +2100,11 @@ pub fn id() -> u32 {
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
     /// This status code is returned to the operating system.
-    #[stable(feature = "termination_trait_lib", since = "1.60.0")]
+    #[stable(feature = "termination_trait_lib", since = "1.61.0")]
     fn report(self) -> ExitCode;
 }
 
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 impl Termination for () {
     #[inline]
     fn report(self) -> ExitCode {
@@ -2112,7 +2112,7 @@ impl Termination for () {
     }
 }
 
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 impl<E: fmt::Debug> Termination for Result<(), E> {
     fn report(self) -> ExitCode {
         match self {
@@ -2122,14 +2122,14 @@ impl<E: fmt::Debug> Termination for Result<(), E> {
     }
 }
 
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 impl Termination for ! {
     fn report(self) -> ExitCode {
         self
     }
 }
 
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
@@ -2138,7 +2138,7 @@ impl<E: fmt::Debug> Termination for Result<!, E> {
     }
 }
 
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 impl<E: fmt::Debug> Termination for Result<Infallible, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
@@ -2146,7 +2146,7 @@ impl<E: fmt::Debug> Termination for Result<Infallible, E> {
     }
 }
 
-#[stable(feature = "termination_trait_lib", since = "1.60.0")]
+#[stable(feature = "termination_trait_lib", since = "1.61.0")]
 impl Termination for ExitCode {
     #[inline]
     fn report(self) -> ExitCode {
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 511de863dc5..d2dd4c075d2 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -91,9 +91,12 @@ use crate::cell::Cell;
 use crate::fmt;
 use crate::marker;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::ptr;
+use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
 use crate::thread::{self, Thread};
 
+type Masked = ();
+
 /// A synchronization primitive which can be used to run a one-time global
 /// initialization. Useful for one-time initialization for FFI or related
 /// functionality. This type can only be constructed with [`Once::new()`].
@@ -113,7 +116,7 @@ use crate::thread::{self, Thread};
 pub struct Once {
     // `state_and_queue` is actually a pointer to a `Waiter` with extra state
     // bits, so we add the `PhantomData` appropriately.
-    state_and_queue: AtomicUsize,
+    state_and_queue: AtomicPtr<Masked>,
     _marker: marker::PhantomData<*const Waiter>,
 }
 
@@ -136,7 +139,7 @@ impl RefUnwindSafe for Once {}
 #[derive(Debug)]
 pub struct OnceState {
     poisoned: bool,
-    set_state_on_drop_to: Cell<usize>,
+    set_state_on_drop_to: Cell<*mut Masked>,
 }
 
 /// Initialization value for static [`Once`] values.
@@ -184,8 +187,8 @@ struct Waiter {
 // Every node is a struct on the stack of a waiting thread.
 // Will wake up the waiters when it gets dropped, i.e. also on panic.
 struct WaiterQueue<'a> {
-    state_and_queue: &'a AtomicUsize,
-    set_state_on_drop_to: usize,
+    state_and_queue: &'a AtomicPtr<Masked>,
+    set_state_on_drop_to: *mut Masked,
 }
 
 impl Once {
@@ -195,7 +198,10 @@ impl Once {
     #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
     #[must_use]
     pub const fn new() -> Once {
-        Once { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: marker::PhantomData }
+        Once {
+            state_and_queue: AtomicPtr::new(ptr::invalid_mut(INCOMPLETE)),
+            _marker: marker::PhantomData,
+        }
     }
 
     /// Performs an initialization routine once and only once. The given closure
@@ -376,7 +382,7 @@ impl Once {
         // operations visible to us, and, this being a fast path, weaker
         // ordering helps with performance. This `Acquire` synchronizes with
         // `Release` operations on the slow path.
-        self.state_and_queue.load(Ordering::Acquire) == COMPLETE
+        self.state_and_queue.load(Ordering::Acquire).addr() == COMPLETE
     }
 
     // This is a non-generic function to reduce the monomorphization cost of
@@ -395,7 +401,7 @@ impl Once {
     fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
         let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
         loop {
-            match state_and_queue {
+            match state_and_queue.addr() {
                 COMPLETE => break,
                 POISONED if !ignore_poisoning => {
                     // Panic to propagate the poison.
@@ -405,7 +411,7 @@ impl Once {
                     // Try to register this thread as the one RUNNING.
                     let exchange_result = self.state_and_queue.compare_exchange(
                         state_and_queue,
-                        RUNNING,
+                        ptr::invalid_mut(RUNNING),
                         Ordering::Acquire,
                         Ordering::Acquire,
                     );
@@ -417,13 +423,13 @@ impl Once {
                     // wake them up on drop.
                     let mut waiter_queue = WaiterQueue {
                         state_and_queue: &self.state_and_queue,
-                        set_state_on_drop_to: POISONED,
+                        set_state_on_drop_to: ptr::invalid_mut(POISONED),
                     };
                     // Run the initialization function, letting it know if we're
                     // poisoned or not.
                     let init_state = OnceState {
-                        poisoned: state_and_queue == POISONED,
-                        set_state_on_drop_to: Cell::new(COMPLETE),
+                        poisoned: state_and_queue.addr() == POISONED,
+                        set_state_on_drop_to: Cell::new(ptr::invalid_mut(COMPLETE)),
                     };
                     init(&init_state);
                     waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get();
@@ -432,7 +438,7 @@ impl Once {
                 _ => {
                     // All other values must be RUNNING with possibly a
                     // pointer to the waiter queue in the more significant bits.
-                    assert!(state_and_queue & STATE_MASK == RUNNING);
+                    assert!(state_and_queue.addr() & STATE_MASK == RUNNING);
                     wait(&self.state_and_queue, state_and_queue);
                     state_and_queue = self.state_and_queue.load(Ordering::Acquire);
                 }
@@ -441,13 +447,13 @@ impl Once {
     }
 }
 
-fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) {
+fn wait(state_and_queue: &AtomicPtr<Masked>, mut current_state: *mut Masked) {
     // Note: the following code was carefully written to avoid creating a
     // mutable reference to `node` that gets aliased.
     loop {
         // Don't queue this thread if the status is no longer running,
         // otherwise we will not be woken up.
-        if current_state & STATE_MASK != RUNNING {
+        if current_state.addr() & STATE_MASK != RUNNING {
             return;
         }
 
@@ -455,15 +461,15 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) {
         let node = Waiter {
             thread: Cell::new(Some(thread::current())),
             signaled: AtomicBool::new(false),
-            next: (current_state & !STATE_MASK) as *const Waiter,
+            next: current_state.with_addr(current_state.addr() & !STATE_MASK) as *const Waiter,
         };
-        let me = &node as *const Waiter as usize;
+        let me = &node as *const Waiter as *const Masked as *mut Masked;
 
         // Try to slide in the node at the head of the linked list, making sure
         // that another thread didn't just replace the head of the linked list.
         let exchange_result = state_and_queue.compare_exchange(
             current_state,
-            me | RUNNING,
+            me.with_addr(me.addr() | RUNNING),
             Ordering::Release,
             Ordering::Relaxed,
         );
@@ -502,7 +508,7 @@ impl Drop for WaiterQueue<'_> {
             self.state_and_queue.swap(self.set_state_on_drop_to, Ordering::AcqRel);
 
         // We should only ever see an old state which was RUNNING.
-        assert_eq!(state_and_queue & STATE_MASK, RUNNING);
+        assert_eq!(state_and_queue.addr() & STATE_MASK, RUNNING);
 
         // Walk the entire linked list of waiters and wake them up (in lifo
         // order, last to register is first to wake up).
@@ -511,7 +517,8 @@ impl Drop for WaiterQueue<'_> {
             // free `node` if there happens to be has a spurious wakeup.
             // So we have to take out the `thread` field and copy the pointer to
             // `next` first.
-            let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter;
+            let mut queue =
+                state_and_queue.with_addr(state_and_queue.addr() & !STATE_MASK) as *const Waiter;
             while !queue.is_null() {
                 let next = (*queue).next;
                 let thread = (*queue).thread.take().unwrap();
@@ -568,6 +575,6 @@ impl OnceState {
     /// Poison the associated [`Once`] without explicitly panicking.
     // NOTE: This is currently only exposed for the `lazy` module
     pub(crate) fn poison(&self) {
-        self.set_state_on_drop_to.set(POISONED);
+        self.set_state_on_drop_to.set(ptr::invalid_mut(POISONED));
     }
 }
diff --git a/library/std/src/sys/unix/memchr.rs b/library/std/src/sys/unix/memchr.rs
index a9273ea676c..73ba604eccb 100644
--- a/library/std/src/sys/unix/memchr.rs
+++ b/library/std/src/sys/unix/memchr.rs
@@ -9,7 +9,7 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
             haystack.len(),
         )
     };
-    if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
+    if p.is_null() { None } else { Some(p.addr() - haystack.as_ptr().addr()) }
 }
 
 pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
@@ -26,7 +26,9 @@ pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
                 haystack.len(),
             )
         };
-        if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
+        // FIXME: this should *likely* use `offset_from`, but more
+        // investigation is needed (including running tests in miri).
+        if p.is_null() { None } else { Some(p.addr() - haystack.as_ptr().addr()) }
     }
 
     #[cfg(not(target_os = "linux"))]
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 2d5d306ed62..be70d00cb1a 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -505,9 +505,8 @@ pub mod guard {
     #[cfg(target_os = "macos")]
     unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
         let th = libc::pthread_self();
-        let stackaddr =
-            libc::pthread_get_stackaddr_np(th) as usize - libc::pthread_get_stacksize_np(th);
-        Some(stackaddr as *mut libc::c_void)
+        let stackptr = libc::pthread_get_stackaddr_np(th);
+        Some(stackptr.map_addr(|addr| addr - libc::pthread_get_stacksize_np(th)))
     }
 
     #[cfg(target_os = "openbsd")]
@@ -515,14 +514,15 @@ pub mod guard {
         let mut current_stack: libc::stack_t = crate::mem::zeroed();
         assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0);
 
+        let stack_ptr = current_stack.ss_sp;
         let stackaddr = if libc::pthread_main_np() == 1 {
             // main thread
-            current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
+            stack_ptr.addr() - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed)
         } else {
             // new thread
-            current_stack.ss_sp as usize - current_stack.ss_size
+            stack_ptr.addr() - current_stack.ss_size
         };
-        Some(stackaddr as *mut libc::c_void)
+        Some(stack_ptr.with_addr(stack_addr))
     }
 
     #[cfg(any(
@@ -557,7 +557,8 @@ pub mod guard {
     unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
         let page_size = PAGE_SIZE.load(Ordering::Relaxed);
         assert!(page_size != 0);
-        let stackaddr = get_stack_start()?;
+        let stackptr = get_stack_start()?;
+        let stackaddr = stackptr.addr();
 
         // Ensure stackaddr is page aligned! A parent process might
         // have reset RLIMIT_STACK to be non-page aligned. The
@@ -565,11 +566,11 @@ pub mod guard {
         // stackaddr < stackaddr + stacksize, so if stackaddr is not
         // page-aligned, calculate the fix such that stackaddr <
         // new_page_aligned_stackaddr < stackaddr + stacksize
-        let remainder = (stackaddr as usize) % page_size;
+        let remainder = stackaddr % page_size;
         Some(if remainder == 0 {
-            stackaddr
+            stackptr
         } else {
-            ((stackaddr as usize) + page_size - remainder) as *mut libc::c_void
+            stackptr.with_addr(stackaddr + page_size - remainder)
         })
     }
 
@@ -588,8 +589,8 @@ pub mod guard {
             // Instead, we'll just note where we expect rlimit to start
             // faulting, so our handler can report "stack overflow", and
             // trust that the kernel's own stack guard will work.
-            let stackaddr = get_stack_start_aligned()?;
-            let stackaddr = stackaddr as usize;
+            let stackptr = get_stack_start_aligned()?;
+            let stackaddr = stackptr.addr();
             Some(stackaddr - page_size..stackaddr)
         } else if cfg!(all(target_os = "linux", target_env = "musl")) {
             // For the main thread, the musl's pthread_attr_getstack
@@ -602,8 +603,8 @@ pub mod guard {
             // at the bottom.  If we try to remap the bottom of the stack
             // ourselves, FreeBSD's guard page moves upwards.  So we'll just use
             // the builtin guard page.
-            let stackaddr = get_stack_start_aligned()?;
-            let guardaddr = stackaddr as usize;
+            let stackptr = get_stack_start_aligned()?;
+            let guardaddr = stackptr.addr();
             // Technically the number of guard pages is tunable and controlled
             // by the security.bsd.stack_guard_page sysctl, but there are
             // few reasons to change it from the default.  The default value has
@@ -620,25 +621,25 @@ pub mod guard {
             // than the initial mmap() used, so we mmap() here with
             // read/write permissions and only then mprotect() it to
             // no permissions at all. See issue #50313.
-            let stackaddr = get_stack_start_aligned()?;
+            let stackptr = get_stack_start_aligned()?;
             let result = mmap(
-                stackaddr,
+                stackptr,
                 page_size,
                 PROT_READ | PROT_WRITE,
                 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                 -1,
                 0,
             );
-            if result != stackaddr || result == MAP_FAILED {
+            if result != stackptr || result == MAP_FAILED {
                 panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
             }
 
-            let result = mprotect(stackaddr, page_size, PROT_NONE);
+            let result = mprotect(stackptr, page_size, PROT_NONE);
             if result != 0 {
                 panic!("failed to protect the guard page: {}", io::Error::last_os_error());
             }
 
-            let guardaddr = stackaddr as usize;
+            let guardaddr = stackptr.addr();
 
             Some(guardaddr..guardaddr + page_size)
         }
@@ -646,7 +647,8 @@ pub mod guard {
 
     #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
     pub unsafe fn current() -> Option<Guard> {
-        let stackaddr = get_stack_start()? as usize;
+        let stackptr = get_stack_start()?;
+        let stackaddr = stackptr.addr();
         Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr)
     }
 
@@ -679,11 +681,11 @@ pub mod guard {
                     panic!("there is no guard page");
                 }
             }
-            let mut stackaddr = crate::ptr::null_mut();
+            let mut stackptr = crate::ptr::null_mut::<libc::c_void>();
             let mut size = 0;
-            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
+            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
 
-            let stackaddr = stackaddr as usize;
+            let stackaddr = stackptr.addr();
             ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) {
                 Some(stackaddr - guardsize..stackaddr)
             } else if cfg!(all(target_os = "linux", target_env = "musl")) {
diff --git a/library/std/src/sys/windows/alloc.rs b/library/std/src/sys/windows/alloc.rs
index 2fe71f9f28d..fdc81cdea7d 100644
--- a/library/std/src/sys/windows/alloc.rs
+++ b/library/std/src/sys/windows/alloc.rs
@@ -159,7 +159,7 @@ unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 {
         // Create a correctly aligned pointer offset from the start of the allocated block,
         // and write a header before it.
 
-        let offset = layout.align() - (ptr as usize & (layout.align() - 1));
+        let offset = layout.align() - (ptr.addr() & (layout.align() - 1));
         // SAFETY: `MIN_ALIGN` <= `offset` <= `layout.align()` and the size of the allocated
         // block is `layout.align() + layout.size()`. `aligned` will thus be a correctly aligned
         // pointer inside the allocated block with at least `layout.size()` bytes after it and at
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 9b61b2476d5..0edf43e5d9d 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -173,7 +173,7 @@ pub const PROGRESS_CONTINUE: DWORD = 0;
 
 pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
 
-pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+pub const INVALID_HANDLE_VALUE: HANDLE = ptr::invalid_mut(!0);
 
 pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
 
diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs
index cbd3366b189..a914a3bcc12 100644
--- a/library/std/src/sys/windows/compat.rs
+++ b/library/std/src/sys/windows/compat.rs
@@ -88,7 +88,7 @@ macro_rules! compat_fn {
                 let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr();
                 let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8);
                 if !module_handle.is_null() {
-                    match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8) as usize {
+                    match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8).addr() {
                         0 => {}
                         n => {
                             PTR = Some(mem::transmute::<usize, F>(n));
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index d6c40a15329..95903899297 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -57,6 +57,9 @@ pub struct DirEntry {
     data: c::WIN32_FIND_DATAW,
 }
 
+unsafe impl Send for OpenOptions {}
+unsafe impl Sync for OpenOptions {}
+
 #[derive(Clone, Debug)]
 pub struct OpenOptions {
     // generic
@@ -72,7 +75,7 @@ pub struct OpenOptions {
     attributes: c::DWORD,
     share_mode: c::DWORD,
     security_qos_flags: c::DWORD,
-    security_attributes: usize, // FIXME: should be a reference
+    security_attributes: c::LPSECURITY_ATTRIBUTES,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
@@ -187,7 +190,7 @@ impl OpenOptions {
             share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
             attributes: 0,
             security_qos_flags: 0,
-            security_attributes: 0,
+            security_attributes: ptr::null_mut(),
         }
     }
 
@@ -228,7 +231,7 @@ impl OpenOptions {
         self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT;
     }
     pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
-        self.security_attributes = attrs as usize;
+        self.security_attributes = attrs;
     }
 
     fn get_access_mode(&self) -> io::Result<c::DWORD> {
@@ -289,7 +292,7 @@ impl File {
                 path.as_ptr(),
                 opts.get_access_mode()?,
                 opts.share_mode,
-                opts.security_attributes as *mut _,
+                opts.security_attributes,
                 opts.get_creation_mode()?,
                 opts.get_flags_and_attributes(),
                 ptr::null_mut(),
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 62814eaaa56..87e3fec6353 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -136,7 +136,7 @@ pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
             ($($n:literal,)+) => {
                 $(
                     if start[$n] == needle {
-                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
+                        return Some(((&start[$n] as *const u16).addr() - ptr.addr()) / 2);
                     }
                 )+
             }
@@ -149,7 +149,7 @@ pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
 
     for c in start {
         if *c == needle {
-            return Some((c as *const u16 as usize - ptr as usize) / 2);
+            return Some(((c as *const u16).addr() - ptr.addr()) / 2);
         }
     }
     None
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index 450bceae000..bcac996c024 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -134,7 +134,7 @@ impl Drop for Env {
 pub fn env() -> Env {
     unsafe {
         let ch = c::GetEnvironmentStringsW();
-        if ch as usize == 0 {
+        if ch.is_null() {
             panic!("failure getting env string from OS: {}", io::Error::last_os_error());
         }
         Env { base: ch, cur: ch }
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs
index 5888ee8e34b..3497da51dee 100644
--- a/library/std/src/sys/windows/thread_parker.rs
+++ b/library/std/src/sys/windows/thread_parker.rs
@@ -60,7 +60,7 @@
 use crate::convert::TryFrom;
 use crate::ptr;
 use crate::sync::atomic::{
-    AtomicI8, AtomicUsize,
+    AtomicI8, AtomicPtr,
     Ordering::{Acquire, Relaxed, Release},
 };
 use crate::sys::{c, dur2timeout};
@@ -217,8 +217,8 @@ impl Parker {
 }
 
 fn keyed_event_handle() -> c::HANDLE {
-    const INVALID: usize = !0;
-    static HANDLE: AtomicUsize = AtomicUsize::new(INVALID);
+    const INVALID: c::HANDLE = ptr::invalid_mut(!0);
+    static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
     match HANDLE.load(Relaxed) {
         INVALID => {
             let mut handle = c::INVALID_HANDLE_VALUE;
@@ -233,7 +233,7 @@ fn keyed_event_handle() -> c::HANDLE {
                     r => panic!("Unable to create keyed event handle: error {r}"),
                 }
             }
-            match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
+            match HANDLE.compare_exchange(INVALID, handle, Relaxed, Relaxed) {
                 Ok(_) => handle,
                 Err(h) => {
                     // Lost the race to another thread initializing HANDLE before we did.
@@ -241,10 +241,10 @@ fn keyed_event_handle() -> c::HANDLE {
                     unsafe {
                         c::CloseHandle(handle);
                     }
-                    h as c::HANDLE
+                    h
                 }
             }
         }
-        handle => handle as c::HANDLE,
+        handle => handle,
     }
 }
diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs
index 47aff060d6f..7671850ac55 100644
--- a/library/std/src/sys_common/condvar/check.rs
+++ b/library/std/src/sys_common/condvar/check.rs
@@ -1,4 +1,5 @@
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::ptr;
+use crate::sync::atomic::{AtomicPtr, Ordering};
 use crate::sys::locks as imp;
 use crate::sys_common::mutex::MovableMutex;
 
@@ -13,17 +14,18 @@ impl CondvarCheck for Box<imp::Mutex> {
 }
 
 pub struct SameMutexCheck {
-    addr: AtomicUsize,
+    addr: AtomicPtr<()>,
 }
 
 #[allow(dead_code)]
 impl SameMutexCheck {
     pub const fn new() -> Self {
-        Self { addr: AtomicUsize::new(0) }
+        Self { addr: AtomicPtr::new(ptr::null_mut()) }
     }
     pub fn verify(&self, mutex: &MovableMutex) {
-        let addr = mutex.raw() as *const imp::Mutex as usize;
-        match self.addr.compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst) {
+        let addr = mutex.raw() as *const imp::Mutex as *const () as *mut _;
+        match self.addr.compare_exchange(ptr::null_mut(), addr, Ordering::SeqCst, Ordering::SeqCst)
+        {
             Ok(_) => {}               // Stored the address
             Err(n) if n == addr => {} // Lost a race to store the same address
             _ => panic!("attempted to use a condition variable with two mutexes"),
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index a100444f049..ca29261b1c9 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -1071,7 +1071,7 @@ pub mod os {
         pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
             // SAFETY: See the documentation for this method.
             let ptr = unsafe { self.os.get() as *mut Value<T> };
-            if ptr as usize > 1 {
+            if ptr.addr() > 1 {
                 // SAFETY: the check ensured the pointer is safe (its destructor
                 // is not running) + it is coming from a trusted source (self).
                 if let Some(ref value) = unsafe { (*ptr).inner.get() } {
@@ -1090,7 +1090,7 @@ pub mod os {
             // SAFETY: No mutable references are ever handed out meaning getting
             // the value is ok.
             let ptr = unsafe { self.os.get() as *mut Value<T> };
-            if ptr as usize == 1 {
+            if ptr.addr() == 1 {
                 // destructor is running
                 return None;
             }
@@ -1130,7 +1130,7 @@ pub mod os {
         unsafe {
             let ptr = Box::from_raw(ptr as *mut Value<T>);
             let key = ptr.key;
-            key.os.set(1 as *mut u8);
+            key.os.set(ptr::invalid_mut(1));
             drop(ptr);
             key.os.set(ptr::null_mut());
         }
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index 2bc7ffb0c50..5324c6bde4e 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -10,7 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - `llvm-libunwind` now accepts `in-tree` (formerly true), `system` or `no` (formerly false) [#77703](https://github.com/rust-lang/rust/pull/77703)
 - The options `infodir`, `localstatedir`, and `gpg-password-file` are no longer allowed in config.toml. Previously, they were ignored without warning. Note that `infodir` and `localstatedir` are still accepted by `./configure`, with a warning. [#82451](https://github.com/rust-lang/rust/pull/82451)
 - Add options for enabling overflow checks, one for std (`overflow-checks-std`) and one for everything else (`overflow-checks`). Both default to false.
-- Change the names for `dist` commmands to match the component they generate. [#90684](https://github.com/rust-lang/rust/pull/90684)
+- Change the names for `dist` commands to match the component they generate. [#90684](https://github.com/rust-lang/rust/pull/90684)
 
 ### Non-breaking changes
 
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index e7511888114..e816f9b4c07 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -594,7 +594,7 @@ impl<'a> Builder<'a> {
                 dist::RustDev,
                 dist::Extended,
                 // It seems that PlainSourceTarball somehow changes how some of the tools
-                // perceive their dependencies (see #93033) which would invaliate fingerprints
+                // perceive their dependencies (see #93033) which would invalidate fingerprints
                 // and force us to rebuild tools after vendoring dependencies.
                 // To work around this, create the Tarball after building all the tools.
                 dist::PlainSourceTarball,
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 00fc1f04342..afc333b5048 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -703,7 +703,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
     //
     // Note that this is disabled if LLVM itself is disabled or we're in a check
     // build. If we are in a check build we still go ahead here presuming we've
-    // detected that LLVM is alreay built and good to go which helps prevent
+    // detected that LLVM is already built and good to go which helps prevent
     // busting caches (e.g. like #71152).
     if builder.config.llvm_enabled()
         && (builder.kind != Kind::Check
diff --git a/src/test/ui/impl-trait/xcrate.rs b/src/test/ui/impl-trait/xcrate.rs
index b73d2946c2b..fe106ff0557 100644
--- a/src/test/ui/impl-trait/xcrate.rs
+++ b/src/test/ui/impl-trait/xcrate.rs
@@ -5,7 +5,7 @@
 extern crate xcrate;
 
 fn main() {
-//  NOTE line below commeted out due to issue #45994
+//  NOTE line below commented out due to issue #45994
 //  assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10);
     xcrate::return_closure_accessing_internal_fn()();
 }
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index 8c47559b369..57d548f313d 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -26,6 +26,7 @@ fn python() -> &'static str {
     let mut python3 = false;
 
     for dir in env::split_paths(&val) {
+        // `python` should always take precedence over python2 / python3 if it exists
         if dir.join(PYTHON).exists() {
             return PYTHON;
         }
@@ -34,11 +35,14 @@ fn python() -> &'static str {
         python3 |= dir.join(PYTHON3).exists();
     }
 
+    // try 3 before 2
     if python3 {
         PYTHON3
     } else if python2 {
         PYTHON2
     } else {
+        // We would have returned early if we found that python is installed ...
+        // maybe this should panic with an error instead?
         PYTHON
     }
 }