diff --git a/RELEASES.md b/RELEASES.md
index 18492213a5dd3..f5b71f295c629 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -12,6 +12,7 @@ Compiler
 - [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142]
 - [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484]
 - [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484]
+- [Dropped support for all cloudabi targets.][78439]
 
 \* Refer to Rust's [platform support page][forge-platform-support] for more
 information on Rust's tiered platform support.
@@ -77,7 +78,6 @@ Compatibility Notes
 - [`#![test]` as an inner attribute is now considered unstable like other inner macro
   attributes, and reports an error by default through the `soft_unstable` lint.][79003]
 - [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864]
-- [Dropped support for all cloudabi targets.][78439]
 - [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's
   recommended to use the `#[panic_handler]` attribute to provide your own implementation.
 - [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296]
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index a78d692aaa7fb..26111729ba5b2 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
     if enabled.contains(SanitizerSet::THREAD) {
         llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
     }
+    if enabled.contains(SanitizerSet::HWADDRESS) {
+        llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
+    }
 }
 
 /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 326ae354ccf48..8b737c9a2e557 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -440,6 +440,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
             sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
             sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
             sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
+            sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
+            sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
         })
     } else {
         None
@@ -652,6 +654,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
     if config.sanitizer.contains(SanitizerSet::THREAD) {
         passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
     }
+    if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
+        let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
+        passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
+    }
 }
 
 pub(crate) fn link(
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index e82198f8f0c06..8c1740d8f25f0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -131,6 +131,7 @@ pub enum Attribute {
     ReturnsTwice = 25,
     ReadNone = 26,
     InaccessibleMemOnly = 27,
+    SanitizeHWAddress = 28,
 }
 
 /// LLVMIntPredicate
@@ -439,6 +440,8 @@ pub struct SanitizerOptions {
     pub sanitize_memory_recover: bool,
     pub sanitize_memory_track_origins: c_int,
     pub sanitize_thread: bool,
+    pub sanitize_hwaddress: bool,
+    pub sanitize_hwaddress_recover: bool,
 }
 
 /// LLVMRelocMode
@@ -2128,6 +2131,7 @@ extern "C" {
         Recover: bool,
     ) -> &'static mut Pass;
     pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
+    pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
     pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
     pub fn LLVMRustAddLastExtensionPasses(
         PMB: &PassManagerBuilder,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8bc4e64422370..6c58417590e69 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -893,6 +893,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
     if sanitizer.contains(SanitizerSet::THREAD) {
         link_sanitizer_runtime(sess, linker, "tsan");
     }
+    if sanitizer.contains(SanitizerSet::HWADDRESS) {
+        link_sanitizer_runtime(sess, linker, "hwasan");
+    }
 }
 
 fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 57b8664d3b605..0e3bf5615af7b 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
   ReturnsTwice = 25,
   ReadNone = 26,
   InaccessibleMemOnly = 27,
+  SanitizeHWAddress = 28,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 2264908995bb7..5263d5dcf3e8f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -33,6 +33,7 @@
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
+#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
 #include "llvm/Transforms/Utils/NameAnonGlobals.h"
 
@@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
   return wrap(createThreadSanitizerLegacyPassPass());
 }
 
+extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
+  const bool CompileKernel = false;
+
+  return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
+}
+
 extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
   assert(RustPass);
   Pass *Pass = unwrap(RustPass);
@@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
   bool SanitizeMemoryRecover;
   int  SanitizeMemoryTrackOrigins;
   bool SanitizeThread;
+  bool SanitizeHWAddress;
+  bool SanitizeHWAddressRecover;
 };
 
 extern "C" void
@@ -886,6 +895,23 @@ LLVMRustOptimizeWithNewPassManager(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
         }
       );
+#endif
+    }
+    if (SanitizerOptions->SanitizeHWAddress) {
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(HWAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
+        }
+      );
+#else
+      PipelineStartEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM) {
+          MPM.addPass(HWAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
+        }
+      );
 #endif
     }
   }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 4118e93074563..45835990cecbb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::ReadNone;
   case InaccessibleMemOnly:
     return Attribute::InaccessibleMemOnly;
+  case SanitizeHWAddress:
+    return Attribute::SanitizeHWAddress;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 0467bf76afecc..98450f5a547da 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -540,7 +540,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         );
     }
 
-    // Attempt to search similar mutable assosiated items for suggestion.
+    // Attempt to search similar mutable associated items for suggestion.
     // In the future, attempt in all path but initially for RHS of for_loop
     fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) {
         let hir = self.infcx.tcx.hir();
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e9ea0ab6f98f5..210dbb0ee9939 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -43,6 +43,7 @@ bitflags! {
         const LEAK    = 1 << 1;
         const MEMORY  = 1 << 2;
         const THREAD  = 1 << 3;
+        const HWADDRESS  = 1 << 4;
     }
 }
 
@@ -56,6 +57,7 @@ impl fmt::Display for SanitizerSet {
                 SanitizerSet::LEAK => "leak",
                 SanitizerSet::MEMORY => "memory",
                 SanitizerSet::THREAD => "thread",
+                SanitizerSet::HWADDRESS => "hwaddress",
                 _ => panic!("unrecognized sanitizer {:?}", s),
             };
             if !first {
@@ -73,12 +75,18 @@ impl IntoIterator for SanitizerSet {
     type IntoIter = std::vec::IntoIter<SanitizerSet>;
 
     fn into_iter(self) -> Self::IntoIter {
-        [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
-            .iter()
-            .copied()
-            .filter(|&s| self.contains(s))
-            .collect::<Vec<_>>()
-            .into_iter()
+        [
+            SanitizerSet::ADDRESS,
+            SanitizerSet::LEAK,
+            SanitizerSet::MEMORY,
+            SanitizerSet::THREAD,
+            SanitizerSet::HWADDRESS,
+        ]
+        .iter()
+        .copied()
+        .filter(|&s| self.contains(s))
+        .collect::<Vec<_>>()
+        .into_iter()
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f78df8a7e29fa..baa0502521da7 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -253,7 +253,7 @@ macro_rules! options {
         pub const parse_passes: &str = "a space-separated list of passes, or `all`";
         pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
         pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
+        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
         pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
         pub const parse_cfguard: &str =
             "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -476,6 +476,7 @@ macro_rules! options {
                         "leak" => SanitizerSet::LEAK,
                         "memory" => SanitizerSet::MEMORY,
                         "thread" => SanitizerSet::THREAD,
+                        "hwaddress" => SanitizerSet::HWADDRESS,
                         _ => return false,
                     }
                 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 69aa72d899fb3..a7ceb9e06a519 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1126,7 +1126,8 @@ impl Session {
         self.opts.optimize != config::OptLevel::No
         // AddressSanitizer uses lifetimes to detect use after scope bugs.
         // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
-        || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
+        // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
+        || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
     }
 
     pub fn link_dead_code(&self) -> bool {
@@ -1562,6 +1563,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         "x86_64-unknown-freebsd",
         "x86_64-unknown-linux-gnu",
     ];
+    const HWASAN_SUPPORTED_TARGETS: &[&str] =
+        &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
 
     // Sanitizers can only be used on some tested platforms.
     for s in sess.opts.debugging_opts.sanitizer {
@@ -1570,6 +1573,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
             SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
             SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
+            SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS,
             _ => panic!("unrecognized sanitizer {}", s),
         };
         if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 20e4f7262acb9..1c37a6b2aca18 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -593,6 +593,7 @@ symbols! {
         html_no_source,
         html_playground_url,
         html_root_url,
+        hwaddress,
         i,
         i128,
         i128_type,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index e5045f906df59..2598f3e38ce00 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -280,7 +280,7 @@ impl ItemCtxt<'tcx> {
         ItemCtxt { tcx, item_def_id }
     }
 
-    pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> {
+    pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         AstConv::ast_ty_to_ty(self, ast_ty)
     }
 
@@ -2709,10 +2709,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.has_name(sym::thread) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
+                    } else if item.has_name(sym::hwaddress) {
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
                     } else {
                         tcx.sess
                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
-                            .note("expected one of: `address`, `memory` or `thread`")
+                            .note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
                             .emit();
                     }
                 }
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index e4eabca9c3b76..7fa58dcd5f44f 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -29,6 +29,73 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
         let parent_node = tcx.hir().get(parent_node_id);
 
         match parent_node {
+            // This match arm is for when the def_id appears in a GAT whose
+            // path can't be resolved without typechecking e.g.
+            //
+            // trait Foo {
+            //   type Assoc<const N: usize>;
+            //   fn foo() -> Self::Assoc<3>;
+            // }
+            //
+            // In the above code we would call this query with the def_id of 3 and
+            // the parent_node we match on would be the hir node for Self::Assoc<3>
+            //
+            // `Self::Assoc<3>` cant be resolved without typchecking here as we
+            // didnt write <Self as Foo>::Assoc<3>. If we did then another match
+            // arm would handle this.
+            //
+            // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
+            Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
+                // Find the Item containing the associated type so we can create an ItemCtxt.
+                // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
+                // ty which is a fully resolved projection.
+                // For the code example above, this would mean converting Self::Assoc<3>
+                // into a ty::Projection(<Self as Foo>::Assoc<3>)
+                let item_hir_id = tcx
+                    .hir()
+                    .parent_iter(hir_id)
+                    .filter(|(_, node)| matches!(node, Node::Item(_)))
+                    .map(|(id, _)| id)
+                    .next()
+                    .unwrap();
+                let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
+                let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
+                let ty = item_ctxt.ast_ty_to_ty(hir_ty);
+
+                // Iterate through the generics of the projection to find the one that corresponds to
+                // the def_id that this query was called with. We filter to only const args here as a
+                // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
+                // but it can't hurt to be safe ^^
+                if let ty::Projection(projection) = ty.kind() {
+                    let generics = tcx.generics_of(projection.item_def_id);
+
+                    let arg_index = segment
+                        .args
+                        .and_then(|args| {
+                            args.args
+                                .iter()
+                                .filter(|arg| arg.is_const())
+                                .position(|arg| arg.id() == hir_id)
+                        })
+                        .unwrap_or_else(|| {
+                            bug!("no arg matching AnonConst in segment");
+                        });
+
+                    return generics
+                        .params
+                        .iter()
+                        .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
+                        .nth(arg_index)
+                        .map(|param| param.def_id);
+                }
+
+                // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(def_id),
+                    "unexpected non-GAT usage of an anon const",
+                );
+                return None;
+            }
             Node::Expr(&Expr {
                 kind:
                     ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index fd44bafab6f76..22d95b8bcc08f 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -56,6 +56,7 @@ This API is completely unstable and subject to change.
 */
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(bindings_after_at)]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
@@ -421,8 +422,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     let env_def_id = tcx.hir().local_def_id(env_node_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
-
-    astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
+    item_cx.to_ty(hir_ty)
 }
 
 pub fn hir_trait_to_predicates<'tcx>(
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 885422732e401..cb772458e50b6 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1622,7 +1622,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 /// `UnsafeCell<T>` is a type that wraps some `T` and indicates unsafe interior operations on the
 /// wrapped type. Types with an `UnsafeCell<T>` field are considered to have an 'unsafe interior'.
 /// The `UnsafeCell<T>` type is the only legal way to obtain aliasable data that is considered
-/// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior.
+/// mutable. In general, transmuting a `&T` type into a `&mut T` is considered undefined behavior.
 ///
 /// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are
 /// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 98b8dca961407..9f98353452006 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -198,12 +198,13 @@ where
                 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
             }
         } else if A::may_have_side_effect() && self.index < self.a.size() {
+            let i = self.index;
+            self.index += 1;
             // match the base implementation's potential side effects
-            // SAFETY: we just checked that `self.index` < `self.a.len()`
+            // SAFETY: we just checked that `i` < `self.a.len()`
             unsafe {
-                self.a.__iterator_get_unchecked(self.index);
+                self.a.__iterator_get_unchecked(i);
             }
-            self.index += 1;
             None
         } else {
             None
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index c9c8f68cd9cce..5bb3f6bdcfd7b 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -76,6 +76,10 @@ pub struct OsString {
     inner: Buf,
 }
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for OsString {}
+
 /// Borrowed reference to an OS string (see [`OsString`]).
 ///
 /// This type represents a borrowed reference to a string in the operating system's preferred
@@ -100,6 +104,10 @@ pub struct OsStr {
     inner: Slice,
 }
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for OsStr {}
+
 impl OsString {
     /// Constructs a new empty `OsString`.
     ///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 961cff661e3ba..d5e00ae4be659 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -582,3 +582,11 @@ include!("keyword_docs.rs");
 // is unconditional, so the unstable feature needs to be defined somewhere.
 #[unstable(feature = "restricted_std", issue = "none")]
 mod __restricted_std_workaround {}
+
+mod sealed {
+    /// This trait being unreachable from outside the crate
+    /// prevents outside implementations of our extension traits.
+    /// This allows adding more trait methods in the future.
+    #[unstable(feature = "sealed", issue = "none")]
+    pub trait Sealed {}
+}
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index fb78e62834a07..6480e654c55f0 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -498,6 +498,10 @@ pub struct Command {
     inner: imp::Command,
 }
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for Command {}
+
 impl Command {
     /// Constructs a new `Command` for launching the program at
     /// path `program`, with the following default configuration:
@@ -1375,6 +1379,10 @@ impl From<fs::File> for Stdio {
 #[stable(feature = "process", since = "1.0.0")]
 pub struct ExitStatus(imp::ExitStatus);
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for ExitStatus {}
+
 impl ExitStatus {
     /// Was termination successful? Signal termination is not considered a
     /// success, and success is defined as a zero exit status.
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
index 724b5dcca6a36..7559c1f1d9e29 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/sys/unix/ext/process.rs
@@ -6,20 +6,16 @@ use crate::ffi::OsStr;
 use crate::io;
 use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 use crate::process;
+use crate::sealed::Sealed;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
-mod private {
-    /// This trait being unreachable from outside the crate
-    /// prevents other implementations of the `ExitStatusExt` trait,
-    /// which allows potentially adding more trait methods in the future.
-    #[stable(feature = "none", since = "1.51.0")]
-    pub trait Sealed {}
-}
-
 /// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait CommandExt {
+pub trait CommandExt: Sealed {
     /// Sets the child process's user ID. This translates to a
     /// `setuid` call in the child process. Failure in the `setuid`
     /// call will cause the spawn to fail.
@@ -193,7 +189,7 @@ impl CommandExt for process::Command {
 /// This trait is sealed: it cannot be implemented outside the standard library.
 /// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait ExitStatusExt: private::Sealed {
+pub trait ExitStatusExt: Sealed {
     /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
     /// a process.
     #[stable(feature = "exit_status_from", since = "1.12.0")]
@@ -228,9 +224,6 @@ pub trait ExitStatusExt: private::Sealed {
     fn into_raw(self) -> i32;
 }
 
-#[stable(feature = "none", since = "1.51.0")]
-impl private::Sealed for process::ExitStatus {}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ExitStatusExt for process::ExitStatus {
     fn from_raw(raw: i32) -> Self {
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index d5e14bec76572..1d1118aa69434 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -22,6 +22,7 @@ use crate::str;
 use crate::sys::cvt;
 use crate::sys::fd;
 use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
+use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock};
 use crate::vec;
 
 use libc::{c_char, c_int, c_void};
@@ -490,20 +491,20 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     extern "C" {
         static mut environ: *const *const c_char;
     }
-    &mut environ
+    ptr::addr_of_mut!(environ)
 }
 
-pub unsafe fn env_lock() -> StaticMutexGuard {
-    // It is UB to attempt to acquire this mutex reentrantly!
-    static ENV_LOCK: StaticMutex = StaticMutex::new();
-    ENV_LOCK.lock()
+static ENV_LOCK: StaticRWLock = StaticRWLock::new();
+
+pub fn env_read_lock() -> RWLockReadGuard {
+    ENV_LOCK.read_with_guard()
 }
 
 /// Returns a vector of (variable, value) byte-vector pairs for all the
 /// environment variables of the current process.
 pub fn env() -> Env {
     unsafe {
-        let _guard = env_lock();
+        let _guard = env_read_lock();
         let mut environ = *environ();
         let mut result = Vec::new();
         if !environ.is_null() {
@@ -540,7 +541,7 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
     // always None as well
     let k = CString::new(k.as_bytes())?;
     unsafe {
-        let _guard = env_lock();
+        let _guard = env_read_lock();
         let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
         let ret = if s.is_null() {
             None
@@ -556,7 +557,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
     let v = CString::new(v.as_bytes())?;
 
     unsafe {
-        let _guard = env_lock();
+        let _guard = ENV_LOCK.write_with_guard();
         cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
     }
 }
@@ -565,7 +566,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
     let nbuf = CString::new(n.as_bytes())?;
 
     unsafe {
-        let _guard = env_lock();
+        let _guard = ENV_LOCK.write_with_guard();
         cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
     }
 }
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 2746f87468dca..9e82df7755e89 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -47,7 +47,7 @@ impl Command {
         // a lock any more because the parent won't do anything and the child is
         // in its own process.
         let result = unsafe {
-            let _env_lock = sys::os::env_lock();
+            let _env_lock = sys::os::env_read_lock();
             cvt(libc::fork())?
         };
 
@@ -124,7 +124,7 @@ impl Command {
                     // Similar to when forking, we want to ensure that access to
                     // the environment is synchronized, so make sure to grab the
                     // environment lock before we try to exec.
-                    let _lock = sys::os::env_lock();
+                    let _lock = sys::os::env_read_lock();
 
                     let Err(e) = self.do_exec(theirs, envp.as_ref());
                     e
@@ -404,7 +404,7 @@ impl Command {
             cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
-            let _env_lock = sys::os::env_lock();
+            let _env_lock = sys::os::env_read_lock();
             let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
             cvt_nz(libc::posix_spawnp(
                 &mut p.pid,
diff --git a/library/std/src/sys/windows/ext/ffi.rs b/library/std/src/sys/windows/ext/ffi.rs
index 1df2a0df143b3..c89b9ff1efa6b 100644
--- a/library/std/src/sys/windows/ext/ffi.rs
+++ b/library/std/src/sys/windows/ext/ffi.rs
@@ -53,6 +53,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::ffi::{OsStr, OsString};
+use crate::sealed::Sealed;
 use crate::sys::os_str::Buf;
 use crate::sys_common::wtf8::Wtf8Buf;
 use crate::sys_common::{AsInner, FromInner};
@@ -61,8 +62,11 @@ use crate::sys_common::{AsInner, FromInner};
 pub use crate::sys_common::wtf8::EncodeWide;
 
 /// Windows-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait OsStringExt {
+pub trait OsStringExt: Sealed {
     /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
     /// 16-bit code units.
     ///
@@ -92,8 +96,11 @@ impl OsStringExt for OsString {
 }
 
 /// Windows-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait OsStrExt {
+pub trait OsStrExt: Sealed {
     /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially
     /// ill-formed UTF-16.
     ///
diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs
index 7a92381d6609b..3d680a7f2d94f 100644
--- a/library/std/src/sys/windows/ext/process.rs
+++ b/library/std/src/sys/windows/ext/process.rs
@@ -4,17 +4,10 @@
 
 use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
 use crate::process;
+use crate::sealed::Sealed;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
-mod private {
-    /// This trait being unreachable from outside the crate
-    /// prevents other implementations of the `ExitStatusExt` trait,
-    /// which allows potentially adding more trait methods in the future.
-    #[stable(feature = "none", since = "1.51.0")]
-    pub trait Sealed {}
-}
-
 #[stable(feature = "process_extensions", since = "1.2.0")]
 impl FromRawHandle for process::Stdio {
     unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
@@ -85,7 +78,7 @@ impl IntoRawHandle for process::ChildStderr {
 /// This trait is sealed: it cannot be implemented outside the standard library.
 /// This is so that future additional methods are not breaking changes.
 #[stable(feature = "exit_status_from", since = "1.12.0")]
-pub trait ExitStatusExt: private::Sealed {
+pub trait ExitStatusExt: Sealed {
     /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
     /// a process.
     #[stable(feature = "exit_status_from", since = "1.12.0")]
@@ -99,12 +92,12 @@ impl ExitStatusExt for process::ExitStatus {
     }
 }
 
-#[stable(feature = "none", since = "1.51.0")]
-impl private::Sealed for process::ExitStatus {}
-
 /// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
-pub trait CommandExt {
+pub trait CommandExt: Sealed {
     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
     ///
     /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs
index 497e5fc7bdd16..302c519740717 100644
--- a/library/std/src/sys_common/os_str_bytes.rs
+++ b/library/std/src/sys_common/os_str_bytes.rs
@@ -6,6 +6,7 @@ use crate::ffi::{OsStr, OsString};
 use crate::fmt;
 use crate::mem;
 use crate::rc::Rc;
+use crate::sealed::Sealed;
 use crate::str;
 use crate::sync::Arc;
 use crate::sys_common::bytestring::debug_fmt_bytestring;
@@ -232,8 +233,11 @@ impl Slice {
 }
 
 /// Platform-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait OsStringExt {
+pub trait OsStringExt: Sealed {
     /// Creates an [`OsString`] from a byte vector.
     ///
     /// See the module documentation for an example.
@@ -258,8 +262,11 @@ impl OsStringExt for OsString {
 }
 
 /// Platform-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait OsStrExt {
+pub trait OsStrExt: Sealed {
     #[stable(feature = "rust1", since = "1.0.0")]
     /// Creates an [`OsStr`] from a byte slice.
     ///
diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs
index 3705d641a1be6..41e8ad7729463 100644
--- a/library/std/src/sys_common/rwlock.rs
+++ b/library/std/src/sys_common/rwlock.rs
@@ -86,3 +86,62 @@ impl RWLock {
         self.0.destroy()
     }
 }
+
+// the cfg annotations only exist due to dead code warnings. the code itself is portable
+#[cfg(unix)]
+pub struct StaticRWLock(RWLock);
+
+#[cfg(unix)]
+impl StaticRWLock {
+    pub const fn new() -> StaticRWLock {
+        StaticRWLock(RWLock::new())
+    }
+
+    /// Acquires shared access to the underlying lock, blocking the current
+    /// thread to do so.
+    ///
+    /// The lock is automatically unlocked when the returned guard is dropped.
+    #[inline]
+    pub fn read_with_guard(&'static self) -> RWLockReadGuard {
+        // Safety: All methods require static references, therefore self
+        // cannot be moved between invocations.
+        unsafe {
+            self.0.read();
+        }
+        RWLockReadGuard(&self.0)
+    }
+
+    /// Acquires write access to the underlying lock, blocking the current thread
+    /// to do so.
+    ///
+    /// The lock is automatically unlocked when the returned guard is dropped.
+    #[inline]
+    pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
+        // Safety: All methods require static references, therefore self
+        // cannot be moved between invocations.
+        unsafe {
+            self.0.write();
+        }
+        RWLockWriteGuard(&self.0)
+    }
+}
+
+#[cfg(unix)]
+pub struct RWLockReadGuard(&'static RWLock);
+
+#[cfg(unix)]
+impl Drop for RWLockReadGuard {
+    fn drop(&mut self) {
+        unsafe { self.0.read_unlock() }
+    }
+}
+
+#[cfg(unix)]
+pub struct RWLockWriteGuard(&'static RWLock);
+
+#[cfg(unix)]
+impl Drop for RWLockWriteGuard {
+    fn drop(&mut self) {
+        unsafe { self.0.write_unlock() }
+    }
+}
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 833c13e9a2615..dee0c15420136 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -1075,8 +1075,11 @@ impl Step for Assemble {
             let src_exe = exe("llvm-dwp", target_compiler.host);
             let dst_exe = exe("rust-llvm-dwp", target_compiler.host);
             let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host });
-            let llvm_bin_dir = llvm_config_bin.parent().unwrap();
-            builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe));
+            if !builder.config.dry_run {
+                let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir"));
+                let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
+                builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe));
+            }
         }
 
         // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 2cabaee68ea67..2e6e9142afe6c 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -51,7 +51,7 @@ def v(*args):
 o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
 o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
 o("vendor", "build.vendor", "enable usage of vendored Rust crates")
-o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
+o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
 o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
 o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
 o("profiler", "build.profiler", "build the profiler runtime")
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index fd0acc3a919b0..22124ec67f5f3 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -29,7 +29,7 @@ fn install_sh(
     let prefix = default_path(&builder.config.prefix, "/usr/local");
     let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
     let datadir = prefix.join(default_path(&builder.config.datadir, "share"));
-    let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc"));
+    let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust"));
     let mandir = prefix.join(default_path(&builder.config.mandir, "share/man"));
     let libdir = prefix.join(default_path(&builder.config.libdir, "lib"));
     let bindir = prefix.join(&builder.config.bindir); // Default in config.rs
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 609ac8b366952..b5a8b694c9420 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -804,7 +804,7 @@ fn supported_sanitizers(
         "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
         "aarch64-unknown-linux-gnu" => {
-            common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
+            common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
         }
         "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index d03d5c7501424..4f7a101d2acbd 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -7,12 +7,15 @@ The tracking issue for this feature is: [#39699](https://github.com/rust-lang/ru
 This feature allows for use of one of following sanitizers:
 
 * [AddressSanitizer][clang-asan] a fast memory error detector.
+* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
+  AddressSanitizer, but based on partial hardware assistance.
 * [LeakSanitizer][clang-lsan] a run-time memory leak detector.
 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
 * [ThreadSanitizer][clang-tsan] a fast data race detector.
 
-To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
-`-Zsanitizer=memory` or `-Zsanitizer=thread`.
+To enable a sanitizer compile with `-Zsanitizer=address`,
+`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
+`-Zsanitizer=thread`.
 
 # AddressSanitizer
 
@@ -174,6 +177,86 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
 ==39249==ABORTING
 ```
 
+# HWAddressSanitizer
+
+HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much
+less memory.
+
+HWAddressSanitizer is supported on the following targets:
+
+* `aarch64-linux-android`
+* `aarch64-unknown-linux-gnu`
+
+HWAddressSanitizer requires `tagged-globals` target feature to instrument
+globals. To enable this target feature compile with `-C
+target-feature=+tagged-globals`
+
+## Example
+
+Heap buffer overflow:
+
+```rust
+fn main() {
+    let xs = vec![0, 1, 2, 3];
+    let _y = unsafe { *xs.as_ptr().offset(4) };
+}
+```
+
+```shell
+$ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C
+linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target
+aarch64-unknown-linux-gnu
+```
+
+```shell
+$ ./main
+==241==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefdeffff0050 at pc 0xaaaae0ae4a98
+READ of size 4 at 0xefdeffff0050 tags: 2c/00 (ptr/mem) in thread T0
+    #0 0xaaaae0ae4a94  (/.../main+0x54a94)
+    ...
+
+[0xefdeffff0040,0xefdeffff0060) is a small allocated heap chunk; size: 32 offset: 16
+0xefdeffff0050 is located 0 bytes to the right of 16-byte region [0xefdeffff0040,0xefdeffff0050)
+allocated here:
+    #0 0xaaaae0acb80c  (/.../main+0x3b80c)
+    ...
+
+Thread: T0 0xeffe00002000 stack: [0xffffc28ad000,0xffffc30ad000) sz: 8388608 tls: [0xffffaa10a020,0xffffaa10a7d0)
+Memory tags around the buggy address (one tag corresponds to 16 bytes):
+  0xfefcefffef80: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffef90: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffefa0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffefb0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffefc0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffefd0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffefe0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefcefffeff0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+=>0xfefceffff000: d7  d7  05  00  2c [00] 00  00  00  00  00  00  00  00  00  00
+  0xfefceffff010: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff020: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff030: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff040: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff050: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff060: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff070: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+  0xfefceffff080: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
+  0xfefcefffeff0: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
+=>0xfefceffff000: ..  ..  8c  ..  .. [..] ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
+  0xfefceffff010: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
+See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags
+Registers where the failure occurred (pc 0xaaaae0ae4a98):
+    x0  2c00efdeffff0050  x1  0000000000000004  x2  0000000000000004  x3  0000000000000000
+    x4  0000fffefc30ac37  x5  000000000000005d  x6  00000ffffc30ac37  x7  0000efff00000000
+    x8  2c00efdeffff0050  x9  0200efff00000000  x10 0000000000000000  x11 0200efff00000000
+    x12 0200effe00000310  x13 0200effe00000310  x14 0000000000000008  x15 5d00ffffc30ac360
+    x16 0000aaaae0ad062c  x17 0000000000000003  x18 0000000000000001  x19 0000ffffc30ac658
+    x20 4e00ffffc30ac6e0  x21 0000aaaae0ac5e10  x22 0000000000000000  x23 0000000000000000
+    x24 0000000000000000  x25 0000000000000000  x26 0000000000000000  x27 0000000000000000
+    x28 0000000000000000  x29 0000ffffc30ac5a0  x30 0000aaaae0ae4a98
+SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94)
+```
+
 # LeakSanitizer
 
 LeakSanitizer is run-time memory leak detector.
@@ -321,11 +404,13 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 
 * [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
 * [AddressSanitizer in Clang][clang-asan]
+* [HWAddressSanitizer in Clang][clang-hwasan]
 * [LeakSanitizer in Clang][clang-lsan]
 * [MemorySanitizer in Clang][clang-msan]
 * [ThreadSanitizer in Clang][clang-tsan]
 
 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
+[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js
index 9c5ac1625afea..a50ed5b662bf6 100644
--- a/src/librustdoc/html/static/storage.js
+++ b/src/librustdoc/html/static/storage.js
@@ -89,35 +89,20 @@ function hasOwnProperty(obj, property) {
     return Object.prototype.hasOwnProperty.call(obj, property);
 }
 
-function usableLocalStorage() {
-    // Check if the browser supports localStorage at all:
-    if (typeof Storage === "undefined") {
-        return false;
-    }
-    // Check if we can access it; this access will fail if the browser
-    // preferences deny access to localStorage, e.g., to prevent storage of
-    // "cookies" (or cookie-likes, as is the case here).
-    try {
-        return window.localStorage !== null && window.localStorage !== undefined;
-    } catch(err) {
-        // Storage is supported, but browser preferences deny access to it.
-        return false;
-    }
-}
-
 function updateLocalStorage(name, value) {
-    if (usableLocalStorage()) {
-        localStorage[name] = value;
-    } else {
-        // No Web Storage support so we do nothing
+    try {
+        window.localStorage.setItem(name, value);
+    } catch(e) {
+        // localStorage is not accessible, do nothing
     }
 }
 
 function getCurrentValue(name) {
-    if (usableLocalStorage() && localStorage[name] !== undefined) {
-        return localStorage[name];
+    try {
+        return window.localStorage.getItem(name);
+    } catch(e) {
+        return null;
     }
-    return null;
 }
 
 function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs
new file mode 100644
index 0000000000000..ab33ef6f2442c
--- /dev/null
+++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+// This test unsures that with_opt_const_param returns the
+// def_id of the N param in the Foo::Assoc GAT.
+
+trait Foo {
+    type Assoc<const N: usize>;
+    fn foo(&self) -> Self::Assoc<3>;
+}
+
+impl Foo for () {
+    type Assoc<const N: usize> = [(); N];
+    fn foo(&self) -> Self::Assoc<3> {
+        [(); 3]
+    }
+}
+
+fn main() {
+    assert_eq!(().foo(), [(); 3]);
+}
diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs
new file mode 100644
index 0000000000000..ba9a82ae72109
--- /dev/null
+++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+// This test unsures that with_opt_const_param returns the
+// def_id of the N param in the Foo::Assoc GAT.
+
+trait Foo {
+    type Assoc<const N: usize>;
+    fn foo<const N: usize>(&self) -> Self::Assoc<N>;
+}
+
+impl Foo for () {
+    type Assoc<const N: usize> = [(); N];
+    fn foo<const N: usize>(&self) -> Self::Assoc<N> {
+        [(); N]
+    }
+}
+
+fn main() {
+    assert_eq!(().foo::<10>(), [(); 10]);
+}
diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs
new file mode 100644
index 0000000000000..9da5334056a37
--- /dev/null
+++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs
@@ -0,0 +1,27 @@
+// run-pass
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+// This test unsures that with_opt_const_param returns the
+// def_id of the N param in the Bar::Assoc GAT.
+
+trait Bar {
+    type Assoc<const N: usize>;
+}
+trait Foo: Bar {
+    fn foo(&self) -> Self::Assoc<3>;
+}
+
+impl Bar for () {
+    type Assoc<const N: usize> = [(); N];
+}
+
+impl Foo for () {
+    fn foo(&self) -> Self::Assoc<3> {
+        [(); 3]
+    }
+}
+
+fn main() {
+    assert_eq!(().foo(), [(); 3]);
+}
diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr
index e9983e5fbd24d..4c0b17c7d3769 100644
--- a/src/test/ui/invalid/invalid-no-sanitize.stderr
+++ b/src/test/ui/invalid/invalid-no-sanitize.stderr
@@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
 LL | #[no_sanitize(brontosaurus)]
    |               ^^^^^^^^^^^^
    |
-   = note: expected one of: `address`, `memory` or `thread`
+   = note: expected one of: `address`, `hwaddress`, `memory` or `thread`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/sanitize/hwaddress.rs b/src/test/ui/sanitize/hwaddress.rs
new file mode 100644
index 0000000000000..ad5d0245457ec
--- /dev/null
+++ b/src/test/ui/sanitize/hwaddress.rs
@@ -0,0 +1,19 @@
+// needs-sanitizer-support
+// needs-sanitizer-hwaddress
+//
+// compile-flags: -Z sanitizer=hwaddress -O -g
+//
+// run-fail
+// error-pattern: HWAddressSanitizer: tag-mismatch
+
+#![feature(test)]
+
+use std::hint::black_box;
+
+fn main() {
+    let xs = vec![0, 1, 2, 3];
+    // Avoid optimizing everything out.
+    let xs = black_box(xs.as_ptr());
+    let code = unsafe { *xs.offset(4) };
+    std::process::exit(code);
+}
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 429a8c98cd57c..ff0d845be937c 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -48,6 +48,7 @@ impl EarlyProps {
         let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
         let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
         let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+        let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
 
         iter_header(testfile, None, rdr, &mut |ln| {
             // we should check if any only-<platform> exists and if it exists
@@ -101,6 +102,10 @@ impl EarlyProps {
                     props.ignore = true;
                 }
 
+                if !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress") {
+                    props.ignore = true;
+                }
+
                 if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
                     props.ignore = true;
                 }
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 292850bd9e277..b302953708c18 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -110,6 +110,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
     "x86_64-unknown-linux-gnu",
 ];
 
+pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
+    &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
+
 const BIG_ENDIAN: &[&str] = &[
     "aarch64_be",
     "armebv7r",