about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock54
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock8
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/type_.rs13
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs30
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/mod.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs17
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs41
-rw-r--r--compiler/rustc_infer/src/traits/util.rs7
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp2
-rw-r--r--compiler/rustc_metadata/src/locator.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs18
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_serialize/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/options.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs9
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs18
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs929
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs36
-rw-r--r--compiler/rustc_target/src/spec/aarch64_linux_android.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs43
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs5
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs7
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs13
-rw-r--r--compiler/rustc_typeck/src/collect.rs13
-rw-r--r--library/core/src/intrinsics.rs1
-rw-r--r--library/core/src/ptr/const_ptr.rs3
-rw-r--r--library/core/src/ptr/mod.rs6
-rw-r--r--library/core/src/ptr/mut_ptr.rs7
-rw-r--r--library/core/src/sync/atomic.rs58
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/unix/thread.rs235
-rw-r--r--library/std/src/thread/mod.rs7
-rw-r--r--library/test/src/console.rs2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md129
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs4
-rw-r--r--src/librustdoc/clean/inline.rs14
-rw-r--r--src/librustdoc/clean/mod.rs260
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs (renamed from src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs)5
-rw-r--r--src/test/codegen/sanitizer-cfi-emit-type-checks.rs (renamed from src/test/codegen/sanitizer_cfi_emit_type_checks.rs)5
-rw-r--r--src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs575
-rw-r--r--src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs31
-rw-r--r--src/test/codegen/sanitizer_cfi_emit_type_metadata.rs31
-rw-r--r--src/test/codegen/sanitizer_scs_attr_check.rs17
-rw-r--r--src/test/ui-fulldeps/gated-plugin.rs1
-rw-r--r--src/test/ui-fulldeps/gated-plugin.stderr4
-rw-r--r--src/test/ui-fulldeps/multiple-plugins.rs1
-rw-r--r--src/test/ui-fulldeps/multiple-plugins.stderr4
-rw-r--r--src/test/ui/argument-suggestions/issue-98894.rs4
-rw-r--r--src/test/ui/argument-suggestions/issue-98894.stderr19
-rw-r--r--src/test/ui/argument-suggestions/issue-98897.rs4
-rw-r--r--src/test/ui/argument-suggestions/issue-98897.stderr19
-rw-r--r--src/test/ui/closures/issue-99565.rs7
-rw-r--r--src/test/ui/closures/issue-99565.stderr14
-rw-r--r--src/test/ui/const-generics/issues/issue-86530.rs1
-rw-r--r--src/test/ui/const-generics/issues/issue-86530.stderr18
-rw-r--r--src/test/ui/const-generics/issues/issue-98629.rs15
-rw-r--r--src/test/ui/const-generics/issues/issue-98629.stderr12
-rw-r--r--src/test/ui/invalid/invalid-no-sanitize.stderr2
-rw-r--r--src/test/ui/issues/issue-23041.stderr2
-rw-r--r--src/test/ui/issues/issue-24013.stderr2
-rw-r--r--src/test/ui/issues/issue-77919.rs1
-rw-r--r--src/test/ui/issues/issue-77919.stderr16
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs14
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr24
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs16
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr24
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits.rs22
-rw-r--r--src/tools/bump-stage0/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr10
-rw-r--r--src/tools/compiletest/src/header.rs5
-rw-r--r--src/tools/compiletest/src/util.rs19
-rw-r--r--src/tools/rustbook/Cargo.toml2
96 files changed, 2586 insertions, 482 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ff73b45634f..ed3e30342f2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1726,18 +1726,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-dependencies = [
- "ahash",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.12.0"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
  "ahash",
  "compiler_builtins",
@@ -1896,12 +1887,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indexmap"
-version = "1.8.2"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
- "hashbrown 0.11.2",
+ "hashbrown",
  "rustc-rayon",
  "serde",
 ]
@@ -2361,9 +2352,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.20"
+version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13cdad8057b09a519c6c63e6d7c93ea854f5d7fbfe284df864d5e1140d215a2d"
+checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2389,9 +2380,9 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "10.0.0"
+version = "10.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c"
+checksum = "cbdc226fa10994e8f66a4d2f6f000148bc563a1c671b6dcd2135737018033d8a"
 dependencies = [
  "log",
  "memmap2",
@@ -2578,25 +2569,13 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.28.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
-dependencies = [
- "crc32fast",
- "flate2",
- "hashbrown 0.11.2",
- "indexmap",
- "memchr",
-]
-
-[[package]]
-name = "object"
 version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 dependencies = [
  "crc32fast",
- "hashbrown 0.12.0",
+ "flate2",
+ "hashbrown",
  "indexmap",
  "memchr",
 ]
@@ -4519,6 +4498,7 @@ dependencies = [
 name = "rustc_symbol_mangling"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
  "punycode",
  "rustc-demangle",
  "rustc_data_structures",
@@ -5067,7 +5047,7 @@ dependencies = [
  "core",
  "dlmalloc",
  "fortanix-sgx-abi",
- "hashbrown 0.12.0",
+ "hashbrown",
  "hermit-abi 0.2.0",
  "libc",
  "miniz_oxide 0.4.0",
@@ -5278,13 +5258,13 @@ dependencies = [
 
 [[package]]
 name = "thorin-dwp"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be"
+checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
 dependencies = [
  "gimli 0.26.1",
- "hashbrown 0.11.2",
- "object 0.28.4",
+ "hashbrown",
+ "object 0.29.0",
  "tracing",
 ]
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 334326e927f..60560b1c00e 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1272,7 +1272,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
                 self.visit_generics(generics);
-                self.with_banned_tilde_const(|this| {
+                self.with_tilde_const_allowed(|this| {
                     walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
                 });
                 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index da18ac7eacb..2f5d1c0432f 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -163,15 +163,15 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "indexmap"
-version = "1.8.0"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
  "hashbrown",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index ec2c1f2ca71..ff71d7a209e 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -19,7 +19,7 @@ gimli = { version = "0.26.0", default-features = false, features = ["write"]}
 object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
-indexmap = "1.8.0"
+indexmap = "1.9.1"
 libloading = { version = "0.6.0", optional = true }
 once_cell = "1.10.0"
 smallvec = "1.8.1"
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 6221a7f6d93..4d40dd0994d 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -784,16 +784,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         // TODO(antoyo)
     }
 
-    fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
-        // Unsupported.
-    }
-
-    fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
-        // Unsupported.
-        self.context.new_rvalue_from_int(self.int_type, 0)
-    }
-
-
     fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index 002b95db36d..68bdb8d4e55 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -1,7 +1,7 @@
 use std::convert::TryInto;
 
 use gccjit::{RValue, Struct, Type};
-use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_middle::{bug, ty};
 use rustc_middle::ty::layout::TyAndLayout;
@@ -290,3 +290,14 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
 
     (result, packed)
 }
+
+impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
+        // Unsupported.
+    }
+
+    fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
+        // Unsupported.
+        self.context.new_rvalue_from_int(self.int_type, 0)
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index d8fbd0a84fb..f9a5463efcd 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -18,7 +18,6 @@ rustc_middle = { path = "../rustc_middle" }
 rustc-demangle = "0.1.21"
 rustc_attr = { path = "../rustc_attr" }
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
-rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fs_util = { path = "../rustc_fs_util" }
@@ -30,6 +29,7 @@ rustc_metadata = { path = "../rustc_metadata" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 62da99ac3fb..1a96dd8bec4 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -69,6 +69,9 @@ pub fn sanitize_attrs<'ll>(
     if enabled.contains(SanitizerSet::HWADDRESS) {
         attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
     }
+    if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
+        attrs.push(llvm::AttributeKind::ShadowCallStack.create_attr(cx.llcx));
+    }
     if enabled.contains(SanitizerSet::MEMTAG) {
         // Check to make sure the mte target feature is actually enabled.
         let features = cx.tcx.global_backend_features(());
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 4a4cccb490d..d3096c73a8a 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -626,32 +626,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
     }
 
-    fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
-        let typeid_metadata = self.typeid_metadata(typeid);
-        let v = [self.const_usize(0), typeid_metadata];
-        unsafe {
-            llvm::LLVMGlobalSetMetadata(
-                function,
-                llvm::MD_type as c_uint,
-                llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
-                    self.cx.llcx,
-                    v.as_ptr(),
-                    v.len() as c_uint,
-                )),
-            )
-        }
-    }
-
-    fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
-        unsafe {
-            llvm::LLVMMDStringInContext(
-                self.cx.llcx,
-                typeid.as_ptr() as *const c_char,
-                typeid.as_bytes().len() as c_uint,
-            )
-        }
-    }
-
     fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 5a5c4f7f860..fa0ecd18fc8 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -18,7 +18,9 @@ use crate::llvm;
 use crate::llvm::AttributePlace::Function;
 use crate::type_::Type;
 use crate::value::Value;
+use rustc_codegen_ssa::traits::TypeMembershipMethods;
 use rustc_middle::ty::Ty;
+use rustc_symbol_mangling::typeid::typeid_for_fnabi;
 use smallvec::SmallVec;
 use tracing::debug;
 
@@ -97,6 +99,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             fn_abi.llvm_type(self),
         );
         fn_abi.apply_attrs_llfn(self, llfn);
+
+        if self.tcx.sess.is_sanitizer_cfi_enabled() {
+            let typeid = typeid_for_fnabi(self.tcx, fn_abi);
+            self.set_type_metadata(llfn, typeid);
+        }
+
         llfn
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 624ce8d9369..f64eb79b0a8 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -192,6 +192,7 @@ pub enum AttributeKind {
     NoUndef = 33,
     SanitizeMemTag = 34,
     NoCfCheck = 35,
+    ShadowCallStack = 36,
 }
 
 /// LLVMIntPredicate
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index cf2d3c423c3..eeb38d4ecf5 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -19,7 +19,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size};
 use std::fmt;
 use std::ptr;
 
-use libc::c_uint;
+use libc::{c_char, c_uint};
 
 impl PartialEq for Type {
     fn eq(&self, other: &Self) -> bool {
@@ -289,3 +289,31 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         ty.llvm_type(self)
     }
 }
+
+impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+    fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
+        let typeid_metadata = self.typeid_metadata(typeid);
+        let v = [self.const_usize(0), typeid_metadata];
+        unsafe {
+            llvm::LLVMGlobalSetMetadata(
+                function,
+                llvm::MD_type as c_uint,
+                llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+                    self.llcx,
+                    v.as_ptr(),
+                    v.len() as c_uint,
+                )),
+            )
+        }
+    }
+
+    fn typeid_metadata(&self, typeid: String) -> &'ll Value {
+        unsafe {
+            llvm::LLVMMDStringInContext(
+                self.llcx,
+                typeid.as_ptr() as *const c_char,
+                typeid.len() as c_uint,
+            )
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 81c8b9ceb13..46d6344dbb2 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -14,7 +14,7 @@ tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
-thorin-dwp = "0.2"
+thorin-dwp = "0.3"
 pathdiff = "0.2.0"
 serde_json = "1.0.59"
 snap = "1"
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 773c55cf551..3eee58d9d1c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
-use rustc_symbol_mangling::typeid_for_fnabi;
+use rustc_symbol_mangling::typeid::typeid_for_fnabi;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, HasDataLayout, WrappingRange};
 use rustc_target::spec::abi::Abi;
@@ -918,7 +918,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // FIXME(rcvalle): Add support for generalized identifiers.
             // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
             let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
-            let typeid_metadata = bx.typeid_metadata(typeid);
+            let typeid_metadata = self.cx.typeid_metadata(typeid);
 
             // Test whether the function pointer is associated with the type identifier.
             let cond = bx.type_test(fn_ptr, typeid_metadata);
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index ec3f7a2156a..8ee375fa9e3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -3,7 +3,6 @@ use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable};
-use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{FnAbi, PassMode};
 
 use std::iter;
@@ -247,13 +246,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     for (bb, _) in traversal::reverse_postorder(&mir) {
         fx.codegen_block(bb);
     }
-
-    // For backends that support CFI using type membership (i.e., testing whether a given  pointer
-    // is associated with a type identifier).
-    if cx.tcx().sess.is_sanitizer_cfi_enabled() {
-        let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
-        bx.type_metadata(llfn, typeid);
-    }
 }
 
 /// Produces, for each argument, a `Value` pointing at the
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 1bbe10141fc..9f49749bb41 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -160,8 +160,6 @@ pub trait BuilderMethods<'a, 'tcx>:
 
     fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
-    fn type_metadata(&mut self, function: Self::Function, typeid: String);
-    fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
     fn store_with_flags(
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 396768e0a42..782fdadbfb8 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -40,7 +40,8 @@ pub use self::intrinsic::IntrinsicCallMethods;
 pub use self::misc::MiscMethods;
 pub use self::statics::{StaticBuilderMethods, StaticMethods};
 pub use self::type_::{
-    ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
+    ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods,
+    TypeMethods,
 };
 pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 5d3f07317a3..8158e8dd011 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -117,6 +117,13 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
     ) -> Self::Type;
 }
 
+// For backends that support CFI using type membership (i.e., testing whether a given  pointer is
+// associated with a type identifier).
+pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> {
+    fn set_type_metadata(&self, function: Self::Function, typeid: String);
+    fn typeid_metadata(&self, typeid: String) -> Self::Value;
+}
+
 pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
     fn store_fn_arg(
         &mut self,
@@ -133,6 +140,12 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
     fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type;
 }
 
-pub trait TypeMethods<'tcx>: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
+pub trait TypeMethods<'tcx>:
+    DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx>
+{
+}
 
-impl<'tcx, T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
+impl<'tcx, T> TypeMethods<'tcx> for T where
+    Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx>
+{
+}
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 2a801d0e702..5c641f54f68 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ doctest = false
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 ena = "0.14"
-indexmap = { version = "1.8.2" }
+indexmap = { version = "1.9.1" }
 tracing = "0.1"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index b267140daa9..561d1354edd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,4 +1,4 @@
-use crate::infer::type_variable::TypeVariableOriginKind;
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::InferCtxt;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -8,12 +8,12 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::ConstVariableOriginKind;
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, InferConst};
-use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
+use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{BytePos, Span};
 use std::borrow::Cow;
@@ -407,11 +407,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
                 err.span_label(span, cannot_infer_msg);
 
-                let printer = fmt_printer(self, Namespace::TypeNS);
-                let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
+                let args = fmt_printer(self, Namespace::TypeNS)
+                    .comma_sep(generic_args.iter().copied().map(|arg| {
+                        if arg.is_suggestable(self.tcx, true) {
+                            return arg;
+                        }
+
+                        match arg.unpack() {
+                            GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
+                            GenericArgKind::Type(_) => self
+                                .next_ty_var(TypeVariableOrigin {
+                                    span: rustc_span::DUMMY_SP,
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                })
+                                .into(),
+                            GenericArgKind::Const(arg) => self
+                                .next_const_var(
+                                    arg.ty(),
+                                    ConstVariableOrigin {
+                                        span: rustc_span::DUMMY_SP,
+                                        kind: ConstVariableOriginKind::MiscVariable,
+                                    },
+                                )
+                                .into(),
+                        }
+                    }))
+                    .unwrap()
+                    .into_buffer();
+
                 err.span_suggestion_verbose(
                     insert_span,
-                    &format!("consider specifying the generic argument{}", pluralize!(args.len()),),
+                    &format!(
+                        "consider specifying the generic argument{}",
+                        pluralize!(generic_args.len()),
+                    ),
                     format!("::<{}>", args),
                     Applicability::HasPlaceholders,
                 );
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 674c75fdee5..38ff9343537 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -145,7 +145,12 @@ impl<'tcx> Elaborator<'tcx> {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let obligations = predicates.predicates.iter().map(|&(pred, _)| {
+                let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
+                    // when parent predicate is non-const, elaborate it to non-const predicates.
+                    if data.constness == ty::BoundConstness::NotConst {
+                        pred = pred.without_const(tcx);
+                    }
+
                     predicate_obligation(
                         pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
                         obligation.param_env,
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 9fe84a6309b..bca5425e728 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
   NoUndef = 33,
   SanitizeMemTag = 34,
   NoCfCheck = 35,
+  ShadowCallStack = 36,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 2d35ee8976e..4615558b912 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -232,6 +232,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::NoUndef;
   case SanitizeMemTag:
     return Attribute::SanitizeMemTag;
+  case ShadowCallStack:
+    return Attribute::ShadowCallStack;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index a72bcb9a2db..2c1c84b0be2 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -67,7 +67,7 @@
 //!
 //! ## What criterion to select on?
 //!
-//! This a pretty tricky area of loading crates. Given a file, how do we know
+//! This is a pretty tricky area of loading crates. Given a file, how do we know
 //! whether it's the right crate? Currently, the rules look along these lines:
 //!
 //! 1. Does the filename match an rlib/dylib pattern? That is to say, does the
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 25bc6dc6167..dd2f4321060 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -3,7 +3,7 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
+    visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy,
     PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 
@@ -82,15 +82,18 @@ pub trait IsSuggestable<'tcx> {
     /// meaningful rendered suggestions when pretty-printed. We leave some
     /// nonsense, such as region vars, since those render as `'_` and are
     /// usually okay to reinterpret as elided lifetimes.
-    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
+    ///
+    /// Only if `infer_suggestable` is true, we consider type and const
+    /// inference variables to be suggestable.
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
 }
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
 where
     T: TypeVisitable<'tcx>,
 {
-    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
-        self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
+        self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
     }
 }
 
@@ -100,7 +103,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
     err: &mut Diagnostic,
     trait_pred: PolyTraitPredicate<'tcx>,
 ) -> bool {
-    if !trait_pred.is_suggestable(tcx) {
+    if !trait_pred.is_suggestable(tcx, false) {
         return false;
     }
 
@@ -419,6 +422,7 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
 
 pub struct IsSuggestableVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
+    infer_suggestable: bool,
 }
 
 impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
@@ -426,6 +430,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
+            Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
+
             FnDef(..)
             | Closure(..)
             | Infer(..)
@@ -479,6 +485,8 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
 
     fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         match c.kind() {
+            ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
+
             ConstKind::Infer(..)
             | ConstKind::Bound(..)
             | ConstKind::Placeholder(..)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 49761023ec3..e739ed678d8 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2111,7 +2111,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             let res = match kind {
                 ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()),
                 NormalRibKind => Res::Err,
-                _ => bug!("Unexpected rib kind {:?}", kind),
+                _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
             };
             self.r.record_partial_res(param.id, PartialRes::new(res));
             rib.bindings.insert(ident, res);
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 5056163b7fe..dbc5c15195c 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-indexmap = "1.8.0"
+indexmap = "1.9.1"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 21b1b0b4ebf..1b583417ca0 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -377,7 +377,7 @@ mod desc {
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_oom_strategy: &str = "either `panic` 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`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
+    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, `shadow-call-stack`, 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`";
@@ -683,6 +683,7 @@ mod parse {
                     "leak" => SanitizerSet::LEAK,
                     "memory" => SanitizerSet::MEMORY,
                     "memtag" => SanitizerSet::MEMTAG,
+                    "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
                     "thread" => SanitizerSet::THREAD,
                     "hwaddress" => SanitizerSet::HWADDRESS,
                     _ => return false,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d15b15f75dd..cb15132bd4b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1284,6 +1284,7 @@ symbols! {
         self_in_typedefs,
         self_struct_ctor,
         semitransparent,
+        shadow_call_stack,
         shl,
         shl_assign,
         should_panic,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index d5befa10e23..b104a40c231 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 doctest = false
 
 [dependencies]
+bitflags = "1.2.1"
 tracing = "0.1"
 punycode = "0.4.0"
 rustc-demangle = "0.1.21"
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index bed0e81e66e..5fc992023ca 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -102,9 +102,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
-use rustc_target::abi::call::FnAbi;
 
 use tracing::debug;
 
@@ -112,6 +111,7 @@ mod legacy;
 mod v0;
 
 pub mod test;
+pub mod typeid;
 
 /// This function computes the symbol name for the given `instance` and the
 /// given instantiating crate. That is, if you know that instance X is
@@ -150,11 +150,6 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty
     ty::SymbolName::new(tcx, &symbol_name)
 }
 
-/// This function computes the typeid for the given function ABI.
-pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
-    v0::mangle_typeid_for_fnabi(tcx, fn_abi)
-}
-
 pub fn typeid_for_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyExistentialTraitRef<'tcx>,
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
new file mode 100644
index 00000000000..9228bea43f9
--- /dev/null
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -0,0 +1,18 @@
+// For more information about type metadata and type metadata identifiers for cross-language LLVM
+// CFI support, see Type metadata in the design document in the tracking issue #89653.
+
+use rustc_middle::ty::{FnSig, Ty, TyCtxt};
+use rustc_target::abi::call::FnAbi;
+
+mod typeid_itanium_cxx_abi;
+use typeid_itanium_cxx_abi::TypeIdOptions;
+
+/// Returns a type metadata identifier for the specified FnAbi.
+pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+    typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS)
+}
+
+/// Returns a type metadata identifier for the specified FnSig.
+pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String {
+    typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS)
+}
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
new file mode 100644
index 00000000000..a09b52fbfdf
--- /dev/null
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -0,0 +1,929 @@
+// For more information about type metadata and type metadata identifiers for cross-language LLVM
+// CFI support, see Type metadata in the design document in the tracking issue #89653.
+
+// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective
+// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C"
+// calling convention to use this encoding for cross-language LLVM CFI.
+
+use bitflags::bitflags;
+use core::fmt::Display;
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
+use rustc_middle::ty::{
+    self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind,
+    Term, Ty, TyCtxt, UintTy,
+};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::sym;
+use rustc_target::abi::call::{Conv, FnAbi};
+use rustc_target::spec::abi::Abi;
+use std::fmt::Write as _;
+
+/// Type and extended type qualifiers.
+#[derive(Eq, Hash, PartialEq)]
+enum TyQ {
+    None,
+    Const,
+    Mut,
+}
+
+/// Substitution dictionary key.
+#[derive(Eq, Hash, PartialEq)]
+enum DictKey<'tcx> {
+    Ty(Ty<'tcx>, TyQ),
+    Region(Region<'tcx>),
+    Const(Const<'tcx>),
+    Predicate(ExistentialPredicate<'tcx>),
+}
+
+bitflags! {
+    /// Options for typeid_for_fnabi and typeid_for_fnsig.
+    pub struct TypeIdOptions: u32 {
+        const NO_OPTIONS = 0;
+        const GENERALIZE_POINTERS = 1;
+        const GENERALIZE_REPR_C = 2;
+    }
+}
+
+/// Options for encode_ty.
+type EncodeTyOptions = TypeIdOptions;
+
+/// Options for transform_ty.
+type TransformTyOptions = TypeIdOptions;
+
+/// Converts a number to a disambiguator (see
+/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
+fn to_disambiguator(num: u64) -> String {
+    if let Some(num) = num.checked_sub(1) {
+        format!("s{}_", base_n::encode(num as u128, 62))
+    } else {
+        "s_".to_string()
+    }
+}
+
+/// Converts a number to a sequence number (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
+fn to_seq_id(num: usize) -> String {
+    if let Some(num) = num.checked_sub(1) {
+        base_n::encode(num as u128, 36).to_uppercase()
+    } else {
+        "".to_string()
+    }
+}
+
+/// Substitutes a component if found in the substitution dictionary (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression>).
+fn compress<'tcx>(
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    key: DictKey<'tcx>,
+    comp: &mut String,
+) {
+    match dict.get(&key) {
+        Some(num) => {
+            comp.clear();
+            let _ = write!(comp, "S{}_", to_seq_id(*num));
+        }
+        None => {
+            dict.insert(key, dict.len());
+        }
+    }
+}
+
+// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly
+// along with other is_c_type methods.
+/// Returns whether a `ty::Ty` is `c_void`.
+fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.kind() {
+        ty::Adt(adt_def, ..) => {
+            let def_id = adt_def.0.did;
+            let crate_name = tcx.crate_name(def_id.krate);
+            if tcx.item_name(def_id).as_str() == "c_void"
+                && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
+            {
+                true
+            } else {
+                false
+            }
+        }
+        _ => false,
+    }
+}
+
+/// Encodes a const using the Itanium C++ ABI as a literal argument (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
+fn encode_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    c: Const<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // L<element-type>[n]<element-value>E as literal argument
+    let mut s = String::from('L');
+
+    // Element type
+    s.push_str(&encode_ty(tcx, c.ty(), dict, options));
+
+    // The only allowed types of const parameters are bool, u8, u16, u32, u64, u128, usize i8, i16,
+    // i32, i64, i128, isize, and char. The bool value false is encoded as 0 and true as 1.
+    fn push_signed_value<T: Display + PartialOrd>(s: &mut String, value: T, zero: T) {
+        if value < zero {
+            s.push('n')
+        };
+        let _ = write!(s, "{}", value);
+    }
+
+    fn push_unsigned_value<T: Display>(s: &mut String, value: T) {
+        let _ = write!(s, "{}", value);
+    }
+
+    if let Some(scalar_int) = c.kind().try_to_scalar_int() {
+        let signed = c.ty().is_signed();
+        match scalar_int.size().bits() {
+            8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
+            16 if signed => push_signed_value(&mut s, scalar_int.try_to_i16().unwrap(), 0),
+            32 if signed => push_signed_value(&mut s, scalar_int.try_to_i32().unwrap(), 0),
+            64 if signed => push_signed_value(&mut s, scalar_int.try_to_i64().unwrap(), 0),
+            128 if signed => push_signed_value(&mut s, scalar_int.try_to_i128().unwrap(), 0),
+            8 => push_unsigned_value(&mut s, scalar_int.try_to_u8().unwrap()),
+            16 => push_unsigned_value(&mut s, scalar_int.try_to_u16().unwrap()),
+            32 => push_unsigned_value(&mut s, scalar_int.try_to_u32().unwrap()),
+            64 => push_unsigned_value(&mut s, scalar_int.try_to_u64().unwrap()),
+            128 => push_unsigned_value(&mut s, scalar_int.try_to_u128().unwrap()),
+            _ => {
+                bug!("encode_const: unexpected size `{:?}`", scalar_int.size().bits());
+            }
+        };
+    } else {
+        bug!("encode_const: unexpected type `{:?}`", c.ty());
+    }
+
+    // Close the "L..E" pair
+    s.push('E');
+
+    compress(dict, DictKey::Const(c), &mut s);
+
+    s
+}
+
+/// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_fnsig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: &FnSig<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: TypeIdOptions,
+) -> String {
+    // Function types are delimited by an "F..E" pair
+    let mut s = String::from("F");
+
+    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
+    match fn_sig.abi {
+        Abi::C { .. } => {
+            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+        _ => {
+            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+    }
+
+    // Encode the return type
+    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits()));
+    let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options);
+    s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
+
+    // Encode the parameter types
+    let tys = fn_sig.inputs();
+    if !tys.is_empty() {
+        for ty in tys {
+            let ty = transform_ty(tcx, *ty, transform_ty_options);
+            s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options));
+        }
+
+        if fn_sig.c_variadic {
+            s.push('z');
+        }
+    } else {
+        if fn_sig.c_variadic {
+            s.push('z');
+        } else {
+            // Empty parameter lists, whether declared as () or conventionally as (void), are
+            // encoded with a void parameter specifier "v".
+            s.push('v')
+        }
+    }
+
+    // Close the "F..E" pair
+    s.push('E');
+
+    s
+}
+
+/// Encodes a predicate using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_predicate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicate: Binder<'tcx, ExistentialPredicate<'tcx>>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>, as vendor
+    // extended type.
+    let mut s = String::new();
+    match predicate.as_ref().skip_binder() {
+        ty::ExistentialPredicate::Trait(trait_ref) => {
+            let name = encode_ty_name(tcx, trait_ref.def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            s.push_str(&encode_substs(tcx, trait_ref.substs, dict, options));
+        }
+        ty::ExistentialPredicate::Projection(projection) => {
+            let name = encode_ty_name(tcx, projection.item_def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            s.push_str(&encode_substs(tcx, projection.substs, dict, options));
+            match projection.term {
+                Term::Ty(ty) => {
+                    s.push_str(&encode_ty(tcx, ty, dict, options));
+                }
+                Term::Const(c) => {
+                    s.push_str(&encode_const(tcx, c, dict, options));
+                }
+            }
+        }
+        ty::ExistentialPredicate::AutoTrait(def_id) => {
+            let name = encode_ty_name(tcx, *def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+        }
+    };
+    compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
+    s
+}
+
+/// Encodes predicates using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_predicates<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicates: &List<Binder<'tcx, ExistentialPredicate<'tcx>>>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // <predicate1[..predicateN]>E as part of vendor extended type
+    let mut s = String::new();
+    let predicates: Vec<Binder<'tcx, ExistentialPredicate<'tcx>>> =
+        predicates.iter().map(|predicate| predicate).collect();
+    for predicate in predicates {
+        s.push_str(&encode_predicate(tcx, predicate, dict, options));
+    }
+    s
+}
+
+/// Encodes a region using the Itanium C++ ABI as a vendor extended type.
+fn encode_region<'tcx>(
+    _tcx: TyCtxt<'tcx>,
+    region: Region<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    _options: EncodeTyOptions,
+) -> String {
+    // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
+    let mut s = String::new();
+    match region.kind() {
+        RegionKind::ReLateBound(debruijn, r) => {
+            s.push_str("u6regionI");
+            // Debruijn index, which identifies the binder, as region disambiguator
+            let num = debruijn.index() as u64;
+            if num > 0 {
+                s.push_str(&to_disambiguator(num));
+            }
+            // Index within the binder
+            let _ = write!(s, "{}", r.var.index() as u64);
+            s.push('E');
+            compress(dict, DictKey::Region(region), &mut s);
+        }
+        RegionKind::ReErased => {
+            s.push_str("u6region");
+            compress(dict, DictKey::Region(region), &mut s);
+        }
+        RegionKind::ReEarlyBound(..)
+        | RegionKind::ReFree(..)
+        | RegionKind::ReStatic
+        | RegionKind::ReVar(..)
+        | RegionKind::RePlaceholder(..)
+        | RegionKind::ReEmpty(..) => {
+            bug!("encode_region: unexpected `{:?}`", region.kind());
+        }
+    }
+    s
+}
+
+/// Encodes substs using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
+/// types that are not used at the FFI boundary.
+fn encode_substs<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    substs: SubstsRef<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // [I<subst1..substN>E] as part of vendor extended type
+    let mut s = String::new();
+    let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect();
+    if !substs.is_empty() {
+        s.push('I');
+        for subst in substs {
+            match subst.unpack() {
+                GenericArgKind::Lifetime(region) => {
+                    s.push_str(&encode_region(tcx, region, dict, options));
+                }
+                GenericArgKind::Type(ty) => {
+                    s.push_str(&encode_ty(tcx, ty, dict, options));
+                }
+                GenericArgKind::Const(c) => {
+                    s.push_str(&encode_const(tcx, c, dict, options));
+                }
+            }
+        }
+        s.push('E');
+    }
+    s
+}
+
+/// Encodes a ty:Ty name, including its crate and path disambiguators and names.
+fn encode_ty_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> String {
+    // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
+    // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
+    //
+    // N<namespace-tagN>..N<namespace-tag1>
+    // C<crate-disambiguator><crate-name>
+    // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
+    //
+    // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
+    //
+    //     pub type Type1 = impl Send;
+    //     let _: Type1 = <Struct1<i32>>::foo;
+    //     fn foo1(_: Type1) { }
+    //
+    //     pub type Type2 = impl Send;
+    //     let _: Type2 = <Trait1<i32>>::foo;
+    //     fn foo2(_: Type2) { }
+    //
+    //     pub type Type3 = impl Send;
+    //     let _: Type3 = <i32 as Trait1<i32>>::foo;
+    //     fn foo3(_: Type3) { }
+    //
+    //     pub type Type4 = impl Send;
+    //     let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
+    //     fn foo3(_: Type4) { }
+    //
+    // Are encoded as:
+    //
+    //     _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
+    //
+    // The reason for not using v0's extended form of paths is to use a consistent and simpler
+    // encoding, as the reasoning for using it isn't relevand for type metadata identifiers (i.e.,
+    // keep symbol names close to how methods are represented in error messages). See
+    // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
+    let mut s = String::new();
+
+    // Start and namespace tags
+    let mut def_path = tcx.def_path(def_id);
+    def_path.data.reverse();
+    for disambiguated_data in &def_path.data {
+        s.push('N');
+        s.push_str(match disambiguated_data.data {
+            hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
+            hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
+            hir::definitions::DefPathData::TypeNs(..) => "t",
+            hir::definitions::DefPathData::ValueNs(..) => "v",
+            hir::definitions::DefPathData::ClosureExpr => "C",
+            hir::definitions::DefPathData::Ctor => "c",
+            hir::definitions::DefPathData::AnonConst => "k",
+            hir::definitions::DefPathData::ImplTrait => "i",
+            hir::definitions::DefPathData::CrateRoot
+            | hir::definitions::DefPathData::Use
+            | hir::definitions::DefPathData::GlobalAsm
+            | hir::definitions::DefPathData::MacroNs(..)
+            | hir::definitions::DefPathData::LifetimeNs(..) => {
+                bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
+            }
+        });
+    }
+
+    // Crate disambiguator and name
+    s.push('C');
+    s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64()));
+    let crate_name = tcx.crate_name(def_path.krate).to_string();
+    let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
+
+    // Disambiguators and names
+    def_path.data.reverse();
+    for disambiguated_data in &def_path.data {
+        let num = disambiguated_data.disambiguator as u64;
+        if num > 0 {
+            s.push_str(&to_disambiguator(num));
+        }
+
+        let name = disambiguated_data.data.to_string();
+        let _ = write!(s, "{}", name.len());
+
+        // Prepend a '_' if name starts with a digit or '_'
+        if let Some(first) = name.as_bytes().get(0) {
+            if first.is_ascii_digit() || *first == b'_' {
+                s.push('_');
+            }
+        } else {
+            bug!("encode_ty_name: invalid name `{:?}`", name);
+        }
+
+        s.push_str(&name);
+    }
+
+    s
+}
+
+/// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
+/// Rust types that are not used at the FFI boundary.
+fn encode_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    let mut typeid = String::new();
+
+    match ty.kind() {
+        // Primitive types
+        ty::Bool => {
+            typeid.push('b');
+        }
+
+        ty::Int(..) | ty::Uint(..) | ty::Float(..) => {
+            // u<length><type-name> as vendor extended type
+            let mut s = String::from(match ty.kind() {
+                ty::Int(IntTy::I8) => "u2i8",
+                ty::Int(IntTy::I16) => "u3i16",
+                ty::Int(IntTy::I32) => "u3i32",
+                ty::Int(IntTy::I64) => "u3i64",
+                ty::Int(IntTy::I128) => "u4i128",
+                ty::Int(IntTy::Isize) => "u5isize",
+                ty::Uint(UintTy::U8) => "u2u8",
+                ty::Uint(UintTy::U16) => "u3u16",
+                ty::Uint(UintTy::U32) => "u3u32",
+                ty::Uint(UintTy::U64) => "u3u64",
+                ty::Uint(UintTy::U128) => "u4u128",
+                ty::Uint(UintTy::Usize) => "u5usize",
+                ty::Float(FloatTy::F32) => "u3f32",
+                ty::Float(FloatTy::F64) => "u3f64",
+                _ => "",
+            });
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Char => {
+            // u4char as vendor extended type
+            let mut s = String::from("u4char");
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Str => {
+            // u3str as vendor extended type
+            let mut s = String::from("u3str");
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Never => {
+            // u5never as vendor extended type
+            let mut s = String::from("u5never");
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Compound types
+        // () in Rust is equivalent to void return type in C
+        _ if ty.is_unit() => {
+            typeid.push('v');
+        }
+
+        // Sequence types
+        ty::Tuple(tys) => {
+            // u5tupleI<element-type1..element-typeN>E as vendor extended type
+            let mut s = String::from("u5tupleI");
+            for ty in tys.iter() {
+                s.push_str(&encode_ty(tcx, ty, dict, options));
+            }
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Array(ty0, len) => {
+            // A<array-length><element-type>
+            let mut s = String::from("A");
+            let _ = write!(s, "{}", &len.kind().try_to_scalar().unwrap().to_u64().unwrap());
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::Slice(ty0) => {
+            // u5sliceI<element-type>E as vendor extended type
+            let mut s = String::from("u5sliceI");
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // User-defined types
+        ty::Adt(adt_def, substs) => {
+            let mut s = String::new();
+            let def_id = adt_def.0.did;
+            if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
+                // For for cross-language CFI support, the encoding must be compatible at the FFI
+                // boundary. For instance:
+                //
+                //     struct type1 {};
+                //     void foo(struct type1* bar) {}
+                //
+                // Is encoded as:
+                //
+                //     _ZTSFvP5type1E
+                //
+                // So, encode any repr(C) user-defined type for extern function types with the "C"
+                // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
+                // <name> is <unscoped-name>.
+                let name = tcx.item_name(def_id).to_string();
+                let _ = write!(s, "{}{}", name.len(), &name);
+                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            } else {
+                // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
+                // <subst>, as vendor extended type.
+                let name = encode_ty_name(tcx, def_id);
+                let _ = write!(s, "u{}{}", name.len(), &name);
+                s.push_str(&encode_substs(tcx, substs, dict, options));
+                compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            }
+            typeid.push_str(&s);
+        }
+
+        ty::Foreign(def_id) => {
+            // <length><name>, where <name> is <unscoped-name>
+            let mut s = String::new();
+            let name = tcx.item_name(*def_id).to_string();
+            let _ = write!(s, "{}{}", name.len(), &name);
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Function types
+        ty::FnDef(def_id, substs)
+        | ty::Closure(def_id, substs)
+        | ty::Generator(def_id, substs, ..) => {
+            // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is <subst>,
+            // as vendor extended type.
+            let mut s = String::new();
+            let name = encode_ty_name(tcx, *def_id);
+            let _ = write!(s, "u{}{}", name.len(), &name);
+            s.push_str(&encode_substs(tcx, substs, dict, options));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Pointer types
+        ty::Ref(region, ty0, ..) => {
+            // [U3mut]u3refI<element-type>E as vendor extended type qualifier and type
+            let mut s = String::new();
+            s.push_str("u3refI");
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            s.push('E');
+            compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s);
+            if ty.is_mutable_ptr() {
+                s = format!("{}{}", "U3mut", &s);
+                compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
+            }
+            typeid.push_str(&s);
+        }
+
+        ty::RawPtr(tm) => {
+            // P[K]<element-type>
+            let mut s = String::new();
+            s.push_str(&encode_ty(tcx, tm.ty, dict, options));
+            if !ty.is_mutable_ptr() {
+                s = format!("{}{}", "K", &s);
+                compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s);
+            };
+            s = format!("{}{}", "P", &s);
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        ty::FnPtr(fn_sig) => {
+            // PF<return-type><parameter-type1..parameter-typeN>E
+            let mut s = String::from("P");
+            s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Trait types
+        ty::Dynamic(predicates, region) => {
+            // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
+            // vendor extended type.
+            let mut s = String::from("u3dynI");
+            s.push_str(&encode_predicates(tcx, predicates, dict, options));
+            s.push_str(&encode_region(tcx, *region, dict, options));
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
+        // Unexpected types
+        ty::Bound(..)
+        | ty::Error(..)
+        | ty::GeneratorWitness(..)
+        | ty::Infer(..)
+        | ty::Opaque(..)
+        | ty::Param(..)
+        | ty::Placeholder(..)
+        | ty::Projection(..) => {
+            bug!("encode_ty: unexpected `{:?}`", ty.kind());
+        }
+    };
+
+    typeid
+}
+
+// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
+// c_void types into unit types unconditionally, and generalizes all pointers if
+// TransformTyOptions::GENERALIZE_POINTERS option is set.
+fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
+    let mut ty = ty;
+
+    match ty.kind() {
+        ty::Bool
+        | ty::Int(..)
+        | ty::Uint(..)
+        | ty::Float(..)
+        | ty::Char
+        | ty::Str
+        | ty::Never
+        | ty::Foreign(..)
+        | ty::Dynamic(..) => {}
+
+        _ if ty.is_unit() => {}
+
+        ty::Tuple(tys) => {
+            ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
+        }
+
+        ty::Array(ty0, len) => {
+            let len = len.kind().try_to_scalar().unwrap().to_u64().unwrap();
+            ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len);
+        }
+
+        ty::Slice(ty0) => {
+            ty = tcx.mk_slice(transform_ty(tcx, *ty0, options));
+        }
+
+        ty::Adt(adt_def, substs) => {
+            if is_c_void_ty(tcx, ty) {
+                ty = tcx.mk_unit();
+            } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
+            {
+                ty = tcx.mk_adt(*adt_def, ty::List::empty());
+            } else if adt_def.repr().transparent() && adt_def.is_struct() {
+                let variant = adt_def.non_enum_variant();
+                let param_env = tcx.param_env(variant.def_id);
+                let field = variant.fields.iter().find(|field| {
+                    let ty = tcx.type_of(field.did);
+                    let is_zst =
+                        tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
+                    !is_zst
+                });
+                if field.is_none() {
+                    // Transform repr(transparent) types without non-ZST field into ()
+                    ty = tcx.mk_unit();
+                } else {
+                    let ty0 = tcx.type_of(field.unwrap().did);
+                    // Generalize any repr(transparent) user-defined type that is either a pointer
+                    // or reference, and either references itself or any other type that contains or
+                    // references itself, to avoid a reference cycle.
+                    if ty0.is_any_ptr() && ty0.contains(ty) {
+                        ty = transform_ty(
+                            tcx,
+                            ty0,
+                            options | TransformTyOptions::GENERALIZE_POINTERS,
+                        );
+                    } else {
+                        ty = transform_ty(tcx, ty0, options);
+                    }
+                }
+            } else {
+                ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
+            }
+        }
+
+        ty::FnDef(def_id, substs) => {
+            ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options));
+        }
+
+        ty::Closure(def_id, substs) => {
+            ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options));
+        }
+
+        ty::Generator(def_id, substs, movability) => {
+            ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability);
+        }
+
+        ty::Ref(region, ty0, ..) => {
+            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit());
+                } else {
+                    ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit());
+                }
+            } else {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options));
+                } else {
+                    ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options));
+                }
+            }
+        }
+
+        ty::RawPtr(tm) => {
+            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ptr(tcx.mk_unit());
+                } else {
+                    ty = tcx.mk_imm_ptr(tcx.mk_unit());
+                }
+            } else {
+                if ty.is_mutable_ptr() {
+                    ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options));
+                } else {
+                    ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options));
+                }
+            }
+        }
+
+        ty::FnPtr(fn_sig) => {
+            if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                ty = tcx.mk_imm_ptr(tcx.mk_unit());
+            } else {
+                let parameters: Vec<Ty<'tcx>> = fn_sig
+                    .skip_binder()
+                    .inputs()
+                    .iter()
+                    .map(|ty| transform_ty(tcx, *ty, options))
+                    .collect();
+                let output = transform_ty(tcx, fn_sig.skip_binder().output(), options);
+                ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars(
+                    tcx.mk_fn_sig(
+                        parameters.iter(),
+                        &output,
+                        fn_sig.c_variadic(),
+                        fn_sig.unsafety(),
+                        fn_sig.abi(),
+                    ),
+                    fn_sig.bound_vars(),
+                ));
+            }
+        }
+
+        ty::Bound(..)
+        | ty::Error(..)
+        | ty::GeneratorWitness(..)
+        | ty::Infer(..)
+        | ty::Opaque(..)
+        | ty::Param(..)
+        | ty::Placeholder(..)
+        | ty::Projection(..) => {
+            bug!("transform_ty: unexpected `{:?}`", ty.kind());
+        }
+    }
+
+    ty
+}
+
+/// Transforms substs for being encoded and used in the substitution dictionary.
+fn transform_substs<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    substs: SubstsRef<'tcx>,
+    options: TransformTyOptions,
+) -> SubstsRef<'tcx> {
+    let substs: Vec<GenericArg<'tcx>> = substs
+        .iter()
+        .map(|subst| {
+            if let GenericArgKind::Type(ty) = subst.unpack() {
+                if is_c_void_ty(tcx, ty) {
+                    tcx.mk_unit().into()
+                } else {
+                    transform_ty(tcx, ty, options).into()
+                }
+            } else {
+                subst
+            }
+        })
+        .collect();
+    tcx.mk_substs(substs.iter())
+}
+
+/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
+/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+pub fn typeid_for_fnabi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+    options: TypeIdOptions,
+) -> String {
+    // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
+    // its type.
+    let mut typeid = String::from("_Z");
+
+    // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
+    // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
+    // code (i.e., 'TS') prefixed to the type encoding for the function.
+    typeid.push_str("TS");
+
+    // Function types are delimited by an "F..E" pair
+    typeid.push('F');
+
+    // A dictionary of substitution candidates used for compression (see
+    // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
+    let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
+
+    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
+    match fn_abi.conv {
+        Conv::C => {
+            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+        _ => {
+            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+    }
+
+    // Encode the return type
+    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
+    let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options);
+    typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+
+    // Encode the parameter types
+    if !fn_abi.c_variadic {
+        if !fn_abi.args.is_empty() {
+            for arg in fn_abi.args.iter() {
+                let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
+                typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+            }
+        } else {
+            // Empty parameter lists, whether declared as () or conventionally as (void), are
+            // encoded with a void parameter specifier "v".
+            typeid.push('v');
+        }
+    } else {
+        for n in 0..fn_abi.fixed_count {
+            let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options);
+            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+        }
+
+        typeid.push('z');
+    }
+
+    // Close the "F..E" pair
+    typeid.push('E');
+
+    typeid
+}
+
+/// Returns a type metadata identifier for the specified FnSig using the Itanium C++ ABI with vendor
+/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+pub fn typeid_for_fnsig<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: &FnSig<'tcx>,
+    options: TypeIdOptions,
+) -> String {
+    // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
+    // its type.
+    let mut typeid = String::from("_Z");
+
+    // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
+    // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
+    // code (i.e., 'TS') prefixed to the type encoding for the function.
+    typeid.push_str("TS");
+
+    // A dictionary of substitution candidates used for compression (see
+    // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
+    let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
+
+    // Encode the function signature
+    typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));
+
+    typeid
+}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 79e3f10526c..71fa5a44887 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -12,7 +12,6 @@ use rustc_middle::ty::{
     self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy,
 };
 use rustc_span::symbol::kw;
-use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
@@ -59,41 +58,6 @@ pub(super) fn mangle<'tcx>(
     std::mem::take(&mut cx.out)
 }
 
-pub(super) fn mangle_typeid_for_fnabi<'tcx>(
-    _tcx: TyCtxt<'tcx>,
-    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-) -> String {
-    // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
-    // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
-    // associated with a type identifier (i.e., test type membership).
-    //
-    // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
-    // type metadata identifiers for function pointers. The typeinfo name encoding is a
-    // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
-    //
-    // For cross-language LLVM CFI support, a compatible encoding must be used by either
-    //
-    //  a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
-    //     type encodings[4]), or at least types used at the FFI boundary.
-    //  b. Reducing the types to the least common denominator between types used by Clang (or at
-    //     least types used at the FFI boundary) and Rust compilers (if even possible).
-    //  c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
-    //     possibly other compilers).
-    //
-    // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
-    // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
-    // code. Option (c) would require changes to Clang to use the new ABI.
-    //
-    // [1] https://llvm.org/docs/TypeMetadata.html
-    // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
-    // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
-    // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
-    //
-    // FIXME(rcvalle): See comment above.
-    let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
-    format!("typeid{}", arg_count)
-}
-
 pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyExistentialTraitRef<'tcx>,
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index 5e31859aaef..c85f7f62a42 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -17,6 +17,7 @@ pub fn target() -> Target {
             supported_sanitizers: SanitizerSet::CFI
                 | SanitizerSet::HWADDRESS
                 | SanitizerSet::MEMTAG
+                | SanitizerSet::SHADOWCALLSTACK
                 | SanitizerSet::ADDRESS,
             ..super::android_base::opts()
         },
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 1a6bb4a2eaf..f7abeafd38f 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -618,6 +618,7 @@ bitflags::bitflags! {
         const HWADDRESS = 1 << 4;
         const CFI     = 1 << 5;
         const MEMTAG  = 1 << 6;
+        const SHADOWCALLSTACK = 1 << 7;
     }
 }
 
@@ -632,6 +633,7 @@ impl SanitizerSet {
             SanitizerSet::LEAK => "leak",
             SanitizerSet::MEMORY => "memory",
             SanitizerSet::MEMTAG => "memtag",
+            SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
             SanitizerSet::THREAD => "thread",
             SanitizerSet::HWADDRESS => "hwaddress",
             _ => return None,
@@ -666,6 +668,7 @@ impl IntoIterator for SanitizerSet {
             SanitizerSet::LEAK,
             SanitizerSet::MEMORY,
             SanitizerSet::MEMTAG,
+            SanitizerSet::SHADOWCALLSTACK,
             SanitizerSet::THREAD,
             SanitizerSet::HWADDRESS,
         ]
@@ -1960,6 +1963,7 @@ impl Target {
                                 Some("leak") => SanitizerSet::LEAK,
                                 Some("memory") => SanitizerSet::MEMORY,
                                 Some("memtag") => SanitizerSet::MEMTAG,
+                                Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
                                 Some("thread") => SanitizerSet::THREAD,
                                 Some("hwaddress") => SanitizerSet::HWADDRESS,
                                 Some(s) => return Err(format!("unknown sanitizer {}", s)),
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index e6284b1c4ac..decbf013311 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -185,14 +185,20 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
         }
         let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
         match concrete {
-            Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() {
+            Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
+                NotConstEvaluatable::MentionsInfer
+            } else if uv.has_param_types_or_consts() {
                 infcx
                     .tcx
                     .sess
                     .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
                 NotConstEvaluatable::MentionsParam
             } else {
-                NotConstEvaluatable::MentionsInfer
+                let guar = infcx.tcx.sess.delay_span_bug(
+                    span,
+                    format!("Missing value for constant, but no error reported?"),
+                );
+                NotConstEvaluatable::Error(guar)
             }),
             Err(ErrorHandled::Linted) => {
                 let reported = infcx
@@ -240,8 +246,11 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
             Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
                 NotConstEvaluatable::MentionsInfer
-                } else {
+                } else if uv.has_param_types_or_consts() {
                 NotConstEvaluatable::MentionsParam
+            } else {
+                let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
+                NotConstEvaluatable::Error(guar)
             }),
             Err(ErrorHandled::Linted) => {
                 let reported =
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 5636c74452c..7ab85e7fa66 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -378,7 +378,7 @@ fn suggest_restriction<'tcx>(
             replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
                 .to_ty(tcx),
         });
-        if !trait_pred.is_suggestable(tcx) {
+        if !trait_pred.is_suggestable(tcx, false) {
             return;
         }
         // We know we have an `impl Trait` that doesn't satisfy a required projection.
@@ -417,7 +417,7 @@ fn suggest_restriction<'tcx>(
             Applicability::MaybeIncorrect,
         );
     } else {
-        if !trait_pred.is_suggestable(tcx) {
+        if !trait_pred.is_suggestable(tcx, false) {
             return;
         }
         // Trivial case: `T` needs an extra bound: `T: Bound`.
@@ -586,7 +586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // else in the predicate.
                     if !trait_pred.skip_binder().trait_ref.substs[1..]
                         .iter()
-                        .all(|g| g.is_suggestable(self.tcx))
+                        .all(|g| g.is_suggestable(self.tcx, false))
                     {
                         return;
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 6b758ba63cd..414857f0acc 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -85,7 +85,7 @@ pub fn trait_obligations<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_id: hir::HirId,
-    trait_ref: &ty::TraitRef<'tcx>,
+    trait_pred: &ty::TraitPredicate<'tcx>,
     span: Span,
     item: &'tcx hir::Item<'tcx>,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
@@ -98,7 +98,7 @@ pub fn trait_obligations<'a, 'tcx>(
         recursion_depth: 0,
         item: Some(item),
     };
-    wf.compute_trait_ref(trait_ref, Elaborate::All);
+    wf.compute_trait_pred(trait_pred, Elaborate::All);
     debug!(obligations = ?wf.out);
     wf.normalize(infcx)
 }
@@ -123,7 +123,7 @@ pub fn predicate_obligations<'a, 'tcx>(
     // It's ok to skip the binder here because wf code is prepared for it
     match predicate.kind().skip_binder() {
         ty::PredicateKind::Trait(t) => {
-            wf.compute_trait_ref(&t.trait_ref, Elaborate::None);
+            wf.compute_trait_pred(&t, Elaborate::None);
         }
         ty::PredicateKind::RegionOutlives(..) => {}
         ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
@@ -301,11 +301,18 @@ impl<'tcx> WfPredicates<'tcx> {
     }
 
     /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
-    fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
+    fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
         let tcx = self.tcx;
-        let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
+        let trait_ref = &trait_pred.trait_ref;
 
-        debug!("compute_trait_ref obligations {:?}", obligations);
+        // if the trait predicate is not const, the wf obligations should not be const as well.
+        let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
+            self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
+        } else {
+            self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
+        };
+
+        debug!("compute_trait_pred obligations {:?}", obligations);
         let param_env = self.param_env;
         let depth = self.recursion_depth;
 
@@ -685,10 +692,11 @@ impl<'tcx> WfPredicates<'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn nominal_obligations(
+    fn nominal_obligations_inner(
         &mut self,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+        remap_constness: bool,
     ) -> Vec<traits::PredicateObligation<'tcx>> {
         let predicates = self.tcx.predicates_of(def_id);
         let mut origins = vec![def_id; predicates.predicates.len()];
@@ -703,19 +711,38 @@ impl<'tcx> WfPredicates<'tcx> {
         debug_assert_eq!(predicates.predicates.len(), origins.len());
 
         iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
-            .map(|((pred, span), origin_def_id)| {
+            .map(|((mut pred, span), origin_def_id)| {
                 let code = if span.is_dummy() {
                     traits::MiscObligation
                 } else {
                     traits::BindingObligation(origin_def_id, span)
                 };
                 let cause = self.cause(code);
+                if remap_constness {
+                    pred = pred.without_const(self.tcx);
+                }
                 traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
             })
             .filter(|pred| !pred.has_escaping_bound_vars())
             .collect()
     }
 
+    fn nominal_obligations(
+        &mut self,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.nominal_obligations_inner(def_id, substs, false)
+    }
+
+    fn nominal_obligations_without_const(
+        &mut self,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.nominal_obligations_inner(def_id, substs, true)
+    }
+
     fn from_object_ty(
         &mut self,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 5e58f237982..979e997f244 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -280,6 +280,11 @@ fn resolve_associated_item<'tcx>(
                 return Ok(None);
             }
 
+            // If the item does not have a value, then we cannot return an instance.
+            if !leaf_def.item.defaultness.has_value() {
+                return Ok(None);
+            }
+
             let substs = tcx.erase_regions(substs);
 
             // Check if we just resolved an associated `const` declaration from
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 612dc384521..40aa27a29e9 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let param_type = tcx.infer_ctxt().enter(|infcx| {
                             infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
                         });
-                        if param_type.is_suggestable(tcx) {
+                        if param_type.is_suggestable(tcx, false) {
                             err.span_suggestion(
                                 tcx.def_span(src_def_id),
                                 "consider changing this type parameter to be a `const` generic",
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 9e4da058052..7111812f0b0 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2676,7 +2676,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     span,
                     ty,
                     opt_sugg: Some((span, Applicability::MachineApplicable))
-                        .filter(|_| ty.is_suggestable(tcx)),
+                        .filter(|_| ty.is_suggestable(tcx, false)),
                 });
 
                 ty
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 1555f4f3fd6..84d2878308a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1070,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
                     if expected_ty.is_unit() {
                         "()".to_string()
-                    } else if expected_ty.is_suggestable(tcx) {
+                    } else if expected_ty.is_suggestable(tcx, false) {
                         format!("/* {} */", expected_ty)
                     } else {
                         "/* value */".to_string()
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 3e6ff72204f..097fff6418e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -506,7 +506,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (&fn_decl.output, found.is_suggestable(self.tcx), can_suggest, expected.is_unit()) {
+        match (
+            &fn_decl.output,
+            found.is_suggestable(self.tcx, false),
+            can_suggest,
+            expected.is_unit(),
+        ) {
             (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
                 err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
                 true
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 1b80e4edca9..b8e998229ba 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -183,7 +183,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
             // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
             match (tcx.impl_polarity(def_id), impl_.polarity) {
                 (ty::ImplPolarity::Positive, _) => {
-                    check_impl(tcx, item, impl_.self_ty, &impl_.of_trait);
+                    check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness);
                 }
                 (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => {
                     // FIXME(#27579): what amount of WF checking do we need for neg impls?
@@ -1242,6 +1242,7 @@ fn check_impl<'tcx>(
     item: &'tcx hir::Item<'tcx>,
     ast_self_ty: &hir::Ty<'_>,
     ast_trait_ref: &Option<hir::TraitRef<'_>>,
+    constness: hir::Constness,
 ) {
     enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
         match *ast_trait_ref {
@@ -1251,11 +1252,19 @@ fn check_impl<'tcx>(
                 // won't hold).
                 let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
                 let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
+                let trait_pred = ty::TraitPredicate {
+                    trait_ref,
+                    constness: match constness {
+                        hir::Constness::Const => ty::BoundConstness::ConstIfConst,
+                        hir::Constness::NotConst => ty::BoundConstness::NotConst,
+                    },
+                    polarity: ty::ImplPolarity::Positive,
+                };
                 let obligations = traits::wf::trait_obligations(
                     wfcx.infcx,
                     wfcx.param_env,
                     wfcx.body_id,
-                    &trait_ref,
+                    &trait_pred,
                     ast_trait_ref.path.span,
                     item,
                 );
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 24e6a5d3047..c562599e2cc 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1929,7 +1929,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             visitor.visit_ty(ty);
             let mut diag = bad_placeholder(tcx, visitor.0, "return type");
             let ret_ty = fn_sig.skip_binder().output();
-            if ret_ty.is_suggestable(tcx) {
+            if ret_ty.is_suggestable(tcx, false) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
@@ -1938,7 +1938,12 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                 );
             } else if matches!(ret_ty.kind(), ty::FnDef(..)) {
                 let fn_sig = ret_ty.fn_sig(tcx);
-                if fn_sig.skip_binder().inputs_and_output.iter().all(|t| t.is_suggestable(tcx)) {
+                if fn_sig
+                    .skip_binder()
+                    .inputs_and_output
+                    .iter()
+                    .all(|t| t.is_suggestable(tcx, false))
+                {
                     diag.span_suggestion(
                         ty.span,
                         "replace with the correct return type",
@@ -2969,6 +2974,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.has_name(sym::memtag) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
+                    } else if item.has_name(sym::shadow_call_stack) {
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
                     } else if item.has_name(sym::thread) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
                     } else if item.has_name(sym::hwaddress) {
@@ -2976,7 +2983,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                     } else {
                         tcx.sess
                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
-                            .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
+                            .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
                             .emit();
                     }
                 }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index dc82b32214c..9ae31a31aaa 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2625,6 +2625,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
 #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
 #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
 #[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
     extern "rust-intrinsic" {
         #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 55f781ce022..6cdbab30589 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1144,6 +1144,7 @@ impl<T: ?Sized> *const T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn read(self) -> T
     where
         T: Sized,
@@ -1164,6 +1165,7 @@ impl<T: ?Sized> *const T {
     /// [`ptr::read_volatile`]: crate::ptr::read_volatile()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub unsafe fn read_volatile(self) -> T
     where
         T: Sized,
@@ -1183,6 +1185,7 @@ impl<T: ?Sized> *const T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn read_unaligned(self) -> T
     where
         T: Sized,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 62548b5fadd..40e28e636d8 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1095,6 +1095,7 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn read<T>(src: *const T) -> T {
     // We are calling the intrinsics directly to avoid function calls in the generated code
     // as `intrinsics::copy_nonoverlapping` is a wrapper function.
@@ -1194,6 +1195,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
     let mut tmp = MaybeUninit::<T>::uninit();
     // SAFETY: the caller must guarantee that `src` is valid for reads.
@@ -1290,6 +1292,7 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn write<T>(dst: *mut T, src: T) {
     // We are calling the intrinsics directly to avoid function calls in the generated code
     // as `intrinsics::copy_nonoverlapping` is a wrapper function.
@@ -1387,6 +1390,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
     // SAFETY: the caller must guarantee that `dst` is valid for writes.
     // `dst` cannot overlap `src` because the caller has mutable access
@@ -1460,6 +1464,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 /// ```
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
     // SAFETY: the caller must uphold the safety contract for `volatile_load`.
     unsafe {
@@ -1530,6 +1535,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 /// ```
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     // SAFETY: the caller must uphold the safety contract for `volatile_store`.
     unsafe {
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 27e8b20b3c5..e323f63115b 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1258,6 +1258,7 @@ impl<T: ?Sized> *mut T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn read(self) -> T
     where
         T: Sized,
@@ -1278,6 +1279,7 @@ impl<T: ?Sized> *mut T {
     /// [`ptr::read_volatile`]: crate::ptr::read_volatile()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub unsafe fn read_volatile(self) -> T
     where
         T: Sized,
@@ -1297,6 +1299,7 @@ impl<T: ?Sized> *mut T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn read_unaligned(self) -> T
     where
         T: Sized,
@@ -1402,6 +1405,7 @@ impl<T: ?Sized> *mut T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn write(self, val: T)
     where
         T: Sized,
@@ -1420,6 +1424,7 @@ impl<T: ?Sized> *mut T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn write_bytes(self, val: u8, count: usize)
     where
         T: Sized,
@@ -1440,6 +1445,7 @@ impl<T: ?Sized> *mut T {
     /// [`ptr::write_volatile`]: crate::ptr::write_volatile()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub unsafe fn write_volatile(self, val: T)
     where
         T: Sized,
@@ -1459,6 +1465,7 @@ impl<T: ?Sized> *mut T {
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn write_unaligned(self, val: T)
     where
         T: Sized,
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index b636dc491a4..5e2e0c4d8cc 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -449,6 +449,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn load(&self, order: Ordering) -> bool {
         // SAFETY: any data races are prevented by atomic intrinsics and the raw
         // pointer passed in is valid because we got it from a reference.
@@ -476,6 +477,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn store(&self, val: bool, order: Ordering) {
         // SAFETY: any data races are prevented by atomic intrinsics and the raw
         // pointer passed in is valid because we got it from a reference.
@@ -507,6 +509,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn swap(&self, val: bool, order: Ordering) -> bool {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
@@ -563,6 +566,7 @@ impl AtomicBool {
         note = "Use `compare_exchange` or `compare_exchange_weak` instead"
     )]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
         match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
             Ok(x) => x,
@@ -610,6 +614,7 @@ impl AtomicBool {
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[doc(alias = "compare_and_swap")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn compare_exchange(
         &self,
         current: bool,
@@ -664,6 +669,7 @@ impl AtomicBool {
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[doc(alias = "compare_and_swap")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn compare_exchange_weak(
         &self,
         current: bool,
@@ -715,6 +721,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
@@ -756,6 +763,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
         // We can't use atomic_nand here because it can result in a bool with
         // an invalid value. This happens because the atomic operation is done
@@ -807,6 +815,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
@@ -847,6 +856,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
@@ -884,6 +894,7 @@ impl AtomicBool {
     #[inline]
     #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_not(&self, order: Ordering) -> bool {
         self.fetch_xor(true, order)
     }
@@ -958,6 +969,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "atomic_fetch_update", since = "1.53.0")]
     #[cfg(target_has_atomic = "8")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_update<F>(
         &self,
         set_order: Ordering,
@@ -1165,6 +1177,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn load(&self, order: Ordering) -> *mut T {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_load(self.p.get(), order) }
@@ -1193,6 +1206,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn store(&self, ptr: *mut T, order: Ordering) {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe {
@@ -1225,6 +1239,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg(target_has_atomic = "ptr")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_swap(self.p.get(), ptr, order) }
@@ -1280,6 +1295,7 @@ impl<T> AtomicPtr<T> {
         note = "Use `compare_exchange` or `compare_exchange_weak` instead"
     )]
     #[cfg(target_has_atomic = "ptr")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
         match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
             Ok(x) => x,
@@ -1319,6 +1335,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[cfg(target_has_atomic = "ptr")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn compare_exchange(
         &self,
         current: *mut T,
@@ -1367,6 +1384,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[cfg(target_has_atomic = "ptr")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn compare_exchange_weak(
         &self,
         current: *mut T,
@@ -1427,6 +1445,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[stable(feature = "atomic_fetch_update", since = "1.53.0")]
     #[cfg(target_has_atomic = "ptr")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_update<F>(
         &self,
         set_order: Ordering,
@@ -1482,6 +1501,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T {
         self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order)
     }
@@ -1526,6 +1546,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T {
         self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order)
     }
@@ -1561,6 +1582,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T {
         #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
@@ -1604,6 +1626,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T {
         #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
@@ -1662,6 +1685,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T {
         #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
@@ -1719,6 +1743,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T {
         #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
@@ -1774,6 +1799,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[cfg(target_has_atomic = "ptr")]
     #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
         #[cfg(not(bootstrap))]
         // SAFETY: data races are prevented by atomic intrinsics.
@@ -2085,6 +2111,7 @@ macro_rules! atomic_int {
             /// ```
             #[inline]
             #[$stable]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn load(&self, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_load(self.v.get(), order) }
@@ -2111,6 +2138,7 @@ macro_rules! atomic_int {
             /// ```
             #[inline]
             #[$stable]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn store(&self, val: $int_type, order: Ordering) {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_store(self.v.get(), val, order); }
@@ -2138,6 +2166,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_swap(self.v.get(), val, order) }
@@ -2195,6 +2224,7 @@ macro_rules! atomic_int {
                 note = "Use `compare_exchange` or `compare_exchange_weak` instead")
             ]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn compare_and_swap(&self,
                                     current: $int_type,
                                     new: $int_type,
@@ -2248,6 +2278,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable_cxchg]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn compare_exchange(&self,
                                     current: $int_type,
                                     new: $int_type,
@@ -2296,6 +2327,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable_cxchg]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn compare_exchange_weak(&self,
                                          current: $int_type,
                                          new: $int_type,
@@ -2331,6 +2363,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_add(self.v.get(), val, order) }
@@ -2360,6 +2393,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_sub(self.v.get(), val, order) }
@@ -2392,6 +2426,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_and(self.v.get(), val, order) }
@@ -2424,6 +2459,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable_nand]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_nand(self.v.get(), val, order) }
@@ -2456,6 +2492,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_or(self.v.get(), val, order) }
@@ -2488,6 +2525,7 @@ macro_rules! atomic_int {
             #[inline]
             #[$stable]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { atomic_xor(self.v.get(), val, order) }
@@ -2528,6 +2566,7 @@ macro_rules! atomic_int {
             #[inline]
             #[stable(feature = "no_more_cas", since = "1.45.0")]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_update<F>(&self,
                                    set_order: Ordering,
                                    fetch_order: Ordering,
@@ -2581,6 +2620,7 @@ macro_rules! atomic_int {
             #[inline]
             #[stable(feature = "atomic_min_max", since = "1.45.0")]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { $max_fn(self.v.get(), val, order) }
@@ -2626,6 +2666,7 @@ macro_rules! atomic_int {
             #[inline]
             #[stable(feature = "atomic_min_max", since = "1.45.0")]
             #[$cfg_cas]
+            #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
             pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
                 // SAFETY: data races are prevented by atomic intrinsics.
                 unsafe { $min_fn(self.v.get(), val, order) }
@@ -2939,6 +2980,7 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering {
 }
 
 #[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) {
     // SAFETY: the caller must uphold the safety contract for `atomic_store`.
     unsafe {
@@ -2953,6 +2995,7 @@ unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) {
 }
 
 #[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_load`.
     unsafe {
@@ -2968,6 +3011,7 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_swap`.
     unsafe {
@@ -2984,6 +3028,7 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_add`.
     unsafe {
@@ -3000,6 +3045,7 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_sub`.
     unsafe {
@@ -3015,6 +3061,7 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange<T: Copy>(
     dst: *mut T,
     old: T,
@@ -3057,6 +3104,7 @@ unsafe fn atomic_compare_exchange<T: Copy>(
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange_weak<T: Copy>(
     dst: *mut T,
     old: T,
@@ -3099,6 +3147,7 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_and`
     unsafe {
@@ -3114,6 +3163,7 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_nand`
     unsafe {
@@ -3129,6 +3179,7 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_or`
     unsafe {
@@ -3144,6 +3195,7 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_xor`
     unsafe {
@@ -3160,6 +3212,7 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// returns the max value (signed comparison)
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_max`
     unsafe {
@@ -3176,6 +3229,7 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// returns the min value (signed comparison)
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_min`
     unsafe {
@@ -3192,6 +3246,7 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// returns the max value (unsigned comparison)
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umax`
     unsafe {
@@ -3208,6 +3263,7 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// returns the min value (unsigned comparison)
 #[inline]
 #[cfg(target_has_atomic = "8")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umin`
     unsafe {
@@ -3298,6 +3354,7 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "fence"]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub fn fence(order: Ordering) {
     // SAFETY: using an atomic fence is safe.
     unsafe {
@@ -3380,6 +3437,7 @@ pub fn fence(order: Ordering) {
 #[inline]
 #[stable(feature = "compiler_fences", since = "1.21.0")]
 #[rustc_diagnostic_item = "compiler_fence"]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub fn compiler_fence(order: Ordering) {
     // SAFETY: using an atomic fence is safe.
     unsafe {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 9fd426d3ac4..6b0c0ad7c21 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -276,6 +276,7 @@
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
+#![feature(is_some_with)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(mixed_integer_ops)]
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 6533625876f..36a3fa6023b 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -285,7 +285,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
         ))] {
             #[cfg(any(target_os = "android", target_os = "linux"))]
             {
-                let quota = cgroup2_quota().max(1);
+                let quota = cgroups::quota().max(1);
                 let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
                 unsafe {
                     if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 {
@@ -379,49 +379,88 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     }
 }
 
-/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot
-/// be determined or is not set.
 #[cfg(any(target_os = "android", target_os = "linux"))]
-fn cgroup2_quota() -> usize {
+mod cgroups {
+    //! Currently not covered
+    //! * cgroup v2 in non-standard mountpoints
+    //! * paths containing control characters or spaces, since those would be escaped in procfs
+    //!   output and we don't unescape
+    use crate::borrow::Cow;
     use crate::ffi::OsString;
     use crate::fs::{try_exists, File};
     use crate::io::Read;
+    use crate::io::{BufRead, BufReader};
     use crate::os::unix::ffi::OsStringExt;
+    use crate::path::Path;
     use crate::path::PathBuf;
+    use crate::str::from_utf8;
 
-    let mut quota = usize::MAX;
-    if cfg!(miri) {
-        // Attempting to open a file fails under default flags due to isolation.
-        // And Miri does not have parallelism anyway.
-        return quota;
-    }
-
-    let _: Option<()> = try {
-        let mut buf = Vec::with_capacity(128);
-        // find our place in the cgroup hierarchy
-        File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?;
-        let cgroup_path = buf
-            .split(|&c| c == b'\n')
-            .filter_map(|line| {
-                let mut fields = line.splitn(3, |&c| c == b':');
-                // expect cgroupv2 which has an empty 2nd field
-                if fields.nth(1) != Some(b"") {
-                    return None;
-                }
-                let path = fields.last()?;
-                // skip leading slash
-                Some(path[1..].to_owned())
-            })
-            .next()?;
-        let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path));
+    #[derive(PartialEq)]
+    enum Cgroup {
+        V1,
+        V2,
+    }
+
+    /// Returns cgroup CPU quota in core-equivalents, rounded down or usize::MAX if the quota cannot
+    /// be determined or is not set.
+    pub(super) fn quota() -> usize {
+        let mut quota = usize::MAX;
+        if cfg!(miri) {
+            // Attempting to open a file fails under default flags due to isolation.
+            // And Miri does not have parallelism anyway.
+            return quota;
+        }
+
+        let _: Option<()> = try {
+            let mut buf = Vec::with_capacity(128);
+            // find our place in the cgroup hierarchy
+            File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?;
+            let (cgroup_path, version) =
+                buf.split(|&c| c == b'\n').fold(None, |previous, line| {
+                    let mut fields = line.splitn(3, |&c| c == b':');
+                    // 2nd field is a list of controllers for v1 or empty for v2
+                    let version = match fields.nth(1) {
+                        Some(b"") => Cgroup::V2,
+                        Some(controllers)
+                            if from_utf8(controllers)
+                                .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) =>
+                        {
+                            Cgroup::V1
+                        }
+                        _ => return previous,
+                    };
+
+                    // already-found v1 trumps v2 since it explicitly specifies its controllers
+                    if previous.is_some() && version == Cgroup::V2 {
+                        return previous;
+                    }
+
+                    let path = fields.last()?;
+                    // skip leading slash
+                    Some((path[1..].to_owned(), version))
+                })?;
+            let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path));
+
+            quota = match version {
+                Cgroup::V1 => quota_v1(cgroup_path),
+                Cgroup::V2 => quota_v2(cgroup_path),
+            };
+        };
+
+        quota
+    }
+
+    fn quota_v2(group_path: PathBuf) -> usize {
+        let mut quota = usize::MAX;
 
         let mut path = PathBuf::with_capacity(128);
         let mut read_buf = String::with_capacity(20);
 
+        // standard mount location defined in file-hierarchy(7) manpage
         let cgroup_mount = "/sys/fs/cgroup";
 
         path.push(cgroup_mount);
-        path.push(&cgroup_path);
+        path.push(&group_path);
 
         path.push("cgroup.controllers");
 
@@ -432,30 +471,134 @@ fn cgroup2_quota() -> usize {
 
         path.pop();
 
-        while path.starts_with(cgroup_mount) {
-            path.push("cpu.max");
+        let _: Option<()> = try {
+            while path.starts_with(cgroup_mount) {
+                path.push("cpu.max");
+
+                read_buf.clear();
+
+                if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() {
+                    let raw_quota = read_buf.lines().next()?;
+                    let mut raw_quota = raw_quota.split(' ');
+                    let limit = raw_quota.next()?;
+                    let period = raw_quota.next()?;
+                    match (limit.parse::<usize>(), period.parse::<usize>()) {
+                        (Ok(limit), Ok(period)) => {
+                            quota = quota.min(limit / period);
+                        }
+                        _ => {}
+                    }
+                }
 
-            read_buf.clear();
+                path.pop(); // pop filename
+                path.pop(); // pop dir
+            }
+        };
 
-            if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() {
-                let raw_quota = read_buf.lines().next()?;
-                let mut raw_quota = raw_quota.split(' ');
-                let limit = raw_quota.next()?;
-                let period = raw_quota.next()?;
-                match (limit.parse::<usize>(), period.parse::<usize>()) {
-                    (Ok(limit), Ok(period)) => {
-                        quota = quota.min(limit / period);
-                    }
+        quota
+    }
+
+    fn quota_v1(group_path: PathBuf) -> usize {
+        let mut quota = usize::MAX;
+        let mut path = PathBuf::with_capacity(128);
+        let mut read_buf = String::with_capacity(20);
+
+        // Hardcode commonly used locations mentioned in the cgroups(7) manpage
+        // if that doesn't work scan mountinfo and adjust `group_path` for bind-mounts
+        let mounts: &[fn(&Path) -> Option<(_, &Path)>] = &[
+            |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu"), p)),
+            |p| Some((Cow::Borrowed("/sys/fs/cgroup/cpu,cpuacct"), p)),
+            // this can be expensive on systems with tons of mountpoints
+            // but we only get to this point when /proc/self/cgroups explicitly indicated
+            // this process belongs to a cpu-controller cgroup v1 and the defaults didn't work
+            find_mountpoint,
+        ];
+
+        for mount in mounts {
+            let Some((mount, group_path)) = mount(&group_path) else { continue };
+
+            path.clear();
+            path.push(mount.as_ref());
+            path.push(&group_path);
+
+            // skip if we guessed the mount incorrectly
+            if matches!(try_exists(&path), Err(_) | Ok(false)) {
+                continue;
+            }
+
+            while path.starts_with(mount.as_ref()) {
+                let mut parse_file = |name| {
+                    path.push(name);
+                    read_buf.clear();
+
+                    let f = File::open(&path);
+                    path.pop(); // restore buffer before any early returns
+                    f.ok()?.read_to_string(&mut read_buf).ok()?;
+                    let parsed = read_buf.trim().parse::<usize>().ok()?;
+
+                    Some(parsed)
+                };
+
+                let limit = parse_file("cpu.cfs_quota_us");
+                let period = parse_file("cpu.cfs_period_us");
+
+                match (limit, period) {
+                    (Some(limit), Some(period)) => quota = quota.min(limit / period),
                     _ => {}
                 }
+
+                path.pop();
             }
 
-            path.pop(); // pop filename
-            path.pop(); // pop dir
+            // we passed the try_exists above so we should have traversed the correct hierarchy
+            // when reaching this line
+            break;
         }
-    };
 
-    quota
+        quota
+    }
+
+    /// Scan mountinfo for cgroup v1 mountpoint with a cpu controller
+    ///
+    /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip
+    /// over the already-included prefix
+    fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> {
+        let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?);
+        let mut line = String::with_capacity(256);
+        loop {
+            line.clear();
+            if reader.read_line(&mut line).ok()? == 0 {
+                break;
+            }
+
+            let line = line.trim();
+            let mut items = line.split(' ');
+
+            let sub_path = items.nth(3)?;
+            let mount_point = items.next()?;
+            let mount_opts = items.next_back()?;
+            let filesystem_type = items.nth_back(1)?;
+
+            if filesystem_type != "cgroup" || !mount_opts.split(',').any(|opt| opt == "cpu") {
+                // not a cgroup / not a cpu-controller
+                continue;
+            }
+
+            let sub_path = Path::new(sub_path).strip_prefix("/").ok()?;
+
+            if !group_path.starts_with(sub_path) {
+                // this is a bind-mount and the bound subdirectory
+                // does not contain the cgroup this process belongs to
+                continue;
+            }
+
+            let trimmed_group_path = group_path.strip_prefix(sub_path).ok()?;
+
+            return Some((Cow::Owned(mount_point.to_owned()), trimmed_group_path));
+        }
+
+        None
+    }
 }
 
 #[cfg(all(
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index d28c7b58b20..44c8a50fd86 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1577,10 +1577,15 @@ fn _assert_sync_and_send() {
 ///
 /// On Linux:
 /// - It may overcount the amount of parallelism available when limited by a
-///   process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be
+///   process-wide affinity mask or cgroup quotas and `sched_getaffinity()` or cgroup fs can't be
 ///   queried, e.g. due to sandboxing.
 /// - It may undercount the amount of parallelism if the current thread's affinity mask
 ///   does not reflect the process' cpuset, e.g. due to pinned threads.
+/// - If the process is in a cgroup v1 cpu controller, this may need to
+///   scan mountpoints to find the corresponding cgroup v1 controller,
+///   which may take time on systems with large numbers of mountpoints.
+///   (This does not apply to cgroup v2, or to processes not in a
+///   cgroup.)
 ///
 /// On all targets:
 /// - It may overcount the amount of parallelism available when running in a VM
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index dc0123cf432..e9dda98966d 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -137,7 +137,7 @@ impl ConsoleTestState {
 // List the tests to console, and optionally to logfile. Filters are honored.
 pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
     let mut output = match term::stdout() {
-        None => OutputLocation::Raw(io::stdout()),
+        None => OutputLocation::Raw(io::stdout().lock()),
         Some(t) => OutputLocation::Pretty(t),
     };
 
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index e83c4d98cc7..7f7549aaf5a 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -18,11 +18,13 @@ This feature allows for use of one of following sanitizers:
 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
 * [MemTagSanitizer][clang-memtag] fast memory error detector based on
   Armv8.5-A Memory Tagging Extension.
+* [ShadowCallStack][clang-scs] provides backward-edge control flow protection.
 * [ThreadSanitizer][clang-tsan] a fast data race detector.
 
 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
 `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
-`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example:
+`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
+You might also need the `--target` and `build-std` flags. Example:
 ```shell
 $ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
 ```
@@ -191,7 +193,8 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
 
 The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
 provides forward-edge control flow protection for Rust-compiled code only by
-aggregating function pointers in groups identified by their number of arguments.
+aggregating function pointers in groups identified by their return and parameter
+types.
 
 Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
 binaries" (i.e., for when C or C++ and Rust -compiled code share the same
@@ -243,7 +246,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {answer}");
+    println!("The answer is: {}", answer);
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 = unsafe {
@@ -253,18 +256,18 @@ fn main() {
     };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {next_answer}");
+    println!("The next answer is: {}", next_answer);
 }
 ```
 Fig. 1. Modified example from the [Advanced Functions and
 Closures][rust-book-ch19-05] chapter of the [The Rust Programming
 Language][rust-book] book.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ cargo run --release
+   Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
+    Finished release [optimized] target(s) in 0.76s
+     Running `target/release/rust-cfi-1`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 The next answer is: 14
@@ -272,11 +275,11 @@ $
 ```
 Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+   Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
+    Finished release [optimized] target(s) in 3.39s
+     Running `target/release/rust-cfi-1`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 Illegal instruction
@@ -306,25 +309,25 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {answer}");
+    println!("The answer is: {}", answer);
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 =
         unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {next_answer}");
+    println!("The next answer is: {}", next_answer);
 }
 ```
 Fig. 4. Another modified example from the [Advanced Functions and
 Closures][rust-book-ch19-05] chapter of the [The Rust Programming
 Language][rust-book] book.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ cargo run --release
+   Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
+    Finished release [optimized] target(s) in 0.76s
+     Running `target/release/rust-cfi-2`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 The next answer is: 14
@@ -332,11 +335,11 @@ $
 ```
 Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
 
-[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
-
 ```shell
-$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
-$ ./rust_cfi
+$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+   Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
+    Finished release [optimized] target(s) in 3.38s
+     Running `target/release/rust-cfi-2`
 The answer is: 12
 With CFI enabled, you should not see the next answer
 Illegal instruction
@@ -346,14 +349,69 @@ Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
 
 When LLVM CFI is enabled, if there are any attempts to change/hijack control
 flow using an indirect branch/call to a function with different number of
-arguments than intended/passed in the call/branch site, the execution is also
-terminated (see Fig. 6).
+parameters than arguments intended/passed in the call/branch site, the
+execution is also terminated (see Fig. 6).
+
+```rust
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+fn add_two(x: i64) -> i64 {
+    x + 2
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+    f(arg) + f(arg)
+}
+
+fn main() {
+    let answer = do_twice(add_one, 5);
+
+    println!("The answer is: {}", answer);
+
+    println!("With CFI enabled, you should not see the next answer");
+    let f: fn(i32) -> i32 =
+        unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
+    let next_answer = do_twice(f, 5);
 
-Forward-edge control flow protection not only by aggregating function pointers
-in groups identified by their number of arguments, but also their argument
-types, will also be provided in later work by defining and using compatible type
-identifiers (see Type metadata in the design document in the tracking
-issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+    println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 7. Another modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+```shell
+ cargo run --release
+   Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
+    Finished release [optimized] target(s) in 0.74s
+     Running `target/release/rust-cfi-3`
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 8. Build and execution of the modified example with LLVM CFI disabled.
+
+```shell
+$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
+   Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
+    Finished release [optimized] target(s) in 3.40s
+     Running `target/release/rust-cfi-3`
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 9. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to a function with different return and
+parameter types than the return type expected and arguments intended/passed in
+the call/branch site, the execution is also terminated (see Fig. 9).
 
 [rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
 [rust-book]: https://doc.rust-lang.org/book/title-page.html
@@ -513,6 +571,18 @@ To enable this target feature compile with `-C target-feature="+mte"`.
 
 More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
 
+# ShadowCallStack
+
+ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack.
+
+ShadowCallStack requires a platform ABI which reserves `x18` as the instrumentation makes use of this register.
+
+ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and is supported on the following targets:
+
+* `aarch64-linux-android`
+
+A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details.
+
 # ThreadSanitizer
 
 ThreadSanitizer is a data race detection tool. It is supported on the following
@@ -610,4 +680,5 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 [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-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index e6f006135e2..c43fd1ad241 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -121,7 +121,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
                 trait_: Some(trait_ref.clean(self.cx)),
-                for_: ty.clean(self.cx),
+                for_: clean_middle_ty(ty, self.cx, None),
                 items: Vec::new(),
                 polarity,
                 kind: ImplKind::Auto,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 12137667e7b..c64c5895079 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -116,14 +116,14 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             // FIXME(eddyb) compute both `trait_` and `for_` from
                             // the post-inference `trait_ref`, as it's more accurate.
                             trait_: Some(trait_ref.0.clean(cx)),
-                            for_: ty.0.clean(cx),
+                            for_: clean_middle_ty(ty.0, cx, None),
                             items: cx.tcx
                                 .associated_items(impl_def_id)
                                 .in_definition_order()
                                 .map(|x| x.clean(cx))
                                 .collect::<Vec<_>>(),
                             polarity: ty::ImplPolarity::Positive,
-                            kind: ImplKind::Blanket(Box::new(trait_ref.0.self_ty().clean(cx))),
+                            kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
                         })),
                         cfg: None,
                     });
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 6b37b8e4db4..7a4ec889ac7 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -16,8 +16,8 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
 use crate::clean::{
-    self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt,
-    Clean, ImplKind, ItemId, Type, Visibility,
+    self, clean_fn_decl_from_did_and_sig, clean_middle_ty, clean_ty, clean_ty_generics, utils,
+    Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -261,7 +261,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
 
 fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
     let predicates = cx.tcx.explicit_predicates_of(did);
-    let type_ = cx.tcx.type_of(did).clean(cx);
+    let type_ = clean_middle_ty(cx.tcx.type_of(did), cx, Some(did));
 
     clean::Typedef {
         type_,
@@ -357,8 +357,8 @@ pub(crate) fn build_impl(
     };
 
     let for_ = match &impl_item {
-        Some(impl_) => impl_.self_ty.clean(cx),
-        None => tcx.type_of(did).clean(cx),
+        Some(impl_) => clean_ty(impl_.self_ty, cx),
+        None => clean_middle_ty(tcx.type_of(did), cx, Some(did)),
     };
 
     // Only inline impl if the implementing type is
@@ -577,14 +577,14 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
 
 fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
     clean::Constant {
-        type_: cx.tcx.type_of(def_id).clean(cx),
+        type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
         kind: clean::ConstantKind::Extern { def_id },
     }
 }
 
 fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
     clean::Static {
-        type_: cx.tcx.type_of(did).clean(cx),
+        type_: clean_middle_ty(cx.tcx.type_of(did), cx, Some(did)),
         mutability: if mutable { Mutability::Mut } else { Mutability::Not },
         expr: None,
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 43ebaab98db..6160783f652 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -239,11 +239,9 @@ impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
 
 impl<'tcx> Clean<'tcx, Constant> for hir::ConstArg {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant {
+        let def_id = cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id();
         Constant {
-            type_: cx
-                .tcx
-                .type_of(cx.tcx.hir().body_owner_def_id(self.value.body).to_def_id())
-                .clean(cx),
+            type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
             kind: ConstantKind::Anonymous { body: self.value.body },
         }
     }
@@ -297,7 +295,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
                     })
                     .collect();
                 WherePredicate::BoundPredicate {
-                    ty: wbp.bounded_ty.clean(cx),
+                    ty: clean_ty(wbp.bounded_ty, cx),
                     bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
                     bound_params,
                 }
@@ -309,8 +307,8 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
             },
 
             hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
-                lhs: wrp.lhs_ty.clean(cx),
-                rhs: wrp.rhs_ty.clean(cx).into(),
+                lhs: clean_ty(wrp.lhs_ty, cx),
+                rhs: clean_ty(wrp.rhs_ty, cx).into(),
             },
         })
     }
@@ -348,7 +346,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx>
 
         let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
         Some(WherePredicate::BoundPredicate {
-            ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
+            ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
             bounds: vec![poly_trait_ref.clean(cx)],
             bound_params: Vec::new(),
         })
@@ -383,7 +381,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>>
         }
 
         Some(WherePredicate::BoundPredicate {
-            ty: ty.clean(cx),
+            ty: clean_middle_ty(*ty, cx, None),
             bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
             bound_params: Vec::new(),
         })
@@ -393,7 +391,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>>
 impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
         match self {
-            ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            ty::Term::Ty(ty) => Term::Type(clean_middle_ty(*ty, cx, None)),
             ty::Term::Const(c) => Term::Constant(c.clean(cx)),
         }
     }
@@ -402,7 +400,7 @@ impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
 impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
         match self {
-            hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
             hir::Term::Const(c) => {
                 let def_id = cx.tcx.hir().local_def_id(c.hir_id);
                 Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
@@ -425,7 +423,7 @@ fn clean_projection<'tcx>(
 ) -> Type {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
     let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
-    let self_type = ty.self_ty().clean(cx);
+    let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
         cx.tcx.opt_parent(def_id).or(Some(def_id))
     } else {
@@ -476,7 +474,7 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
             }
             ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
                 let default = if has_default {
-                    Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
+                    Some(clean_middle_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
                 } else {
                     None
                 };
@@ -494,7 +492,11 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
                 self.name,
                 GenericParamDefKind::Const {
                     did: self.def_id,
-                    ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)),
+                    ty: Box::new(clean_middle_ty(
+                        cx.tcx.type_of(self.def_id),
+                        cx,
+                        Some(self.def_id),
+                    )),
                     default: match has_default {
                         true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())),
                         false => None,
@@ -546,7 +548,7 @@ fn clean_generic_param<'tcx>(
                 GenericParamDefKind::Type {
                     did: did.to_def_id(),
                     bounds,
-                    default: default.map(|t| t.clean(cx)).map(Box::new),
+                    default: default.map(|t| clean_ty(t, cx)).map(Box::new),
                     synthetic,
                 },
             )
@@ -555,7 +557,7 @@ fn clean_generic_param<'tcx>(
             param.name.ident().name,
             GenericParamDefKind::Const {
                 did: did.to_def_id(),
-                ty: Box::new(ty.clean(cx)),
+                ty: Box::new(clean_ty(ty, cx)),
                 default: default.map(|ct| {
                     let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
                     Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
@@ -752,7 +754,7 @@ fn clean_ty_generics<'tcx>(
         if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
             if let Some(proj) = impl_trait_proj.remove(&idx) {
                 for (trait_did, name, rhs) in proj {
-                    let rhs = rhs.clean(cx);
+                    let rhs = clean_middle_ty(rhs, cx, None);
                     simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
                 }
             }
@@ -926,7 +928,7 @@ fn clean_args_from_types_and_names<'tcx>(
                 if name.is_empty() {
                     name = kw::Underscore;
                 }
-                Argument { name, type_: ty.clean(cx), is_const: false }
+                Argument { name, type_: clean_ty(ty, cx), is_const: false }
             })
             .collect(),
     }
@@ -945,7 +947,7 @@ fn clean_args_from_types_and_body_id<'tcx>(
             .enumerate()
             .map(|(i, ty)| Argument {
                 name: name_from_pat(body.params[i].pat),
-                type_: ty.clean(cx),
+                type_: clean_ty(ty, cx),
                 is_const: false,
             })
             .collect(),
@@ -969,7 +971,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
 
     // We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
     // but shouldn't change any code meaning.
-    let output = match sig.skip_binder().output().clean(cx) {
+    let output = match clean_middle_ty(sig.skip_binder().output(), cx, None) {
         Type::Tuple(inner) if inner.is_empty() => DefaultReturn,
         ty => Return(ty),
     };
@@ -983,7 +985,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
                 .inputs()
                 .iter()
                 .map(|t| Argument {
-                    type_: t.clean(cx),
+                    type_: clean_middle_ty(*t, cx, None),
                     name: names.next().map_or(kw::Empty, |i| i.name),
                     is_const: false,
                 })
@@ -995,7 +997,7 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
 impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
         match *self {
-            Self::Return(typ) => Return(typ.clean(cx)),
+            Self::Return(typ) => Return(clean_ty(typ, cx)),
             Self::DefaultReturn(..) => DefaultReturn,
         }
     }
@@ -1038,10 +1040,10 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
         cx.with_param_env(local_did, |cx| {
             let inner = match self.kind {
                 hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
-                    ty.clean(cx),
+                    clean_ty(ty, cx),
                     ConstantKind::Local { def_id: local_did, body: default },
                 ),
-                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(ty.clean(cx)),
+                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
                     let m = clean_function(cx, sig, self.generics, body);
                     MethodItem(m, None)
@@ -1059,9 +1061,13 @@ impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
                 hir::TraitItemKind::Type(bounds, Some(default)) => {
                     let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
                     let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx);
+                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
                     AssocTypeItem(
-                        Typedef { type_: default.clean(cx), generics, item_type: Some(item_type) },
+                        Typedef {
+                            type_: clean_ty(default, cx),
+                            generics,
+                            item_type: Some(item_type),
+                        },
                         bounds,
                     )
                 }
@@ -1086,7 +1092,7 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
             let inner = match self.kind {
                 hir::ImplItemKind::Const(ty, expr) => {
                     let default = ConstantKind::Local { def_id: local_did, body: expr };
-                    AssocConstItem(ty.clean(cx), default)
+                    AssocConstItem(clean_ty(ty, cx), default)
                 }
                 hir::ImplItemKind::Fn(ref sig, body) => {
                     let m = clean_function(cx, sig, self.generics, body);
@@ -1094,9 +1100,9 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
                     MethodItem(m, Some(defaultness))
                 }
                 hir::ImplItemKind::TyAlias(hir_ty) => {
-                    let type_ = hir_ty.clean(cx);
+                    let type_ = clean_ty(hir_ty, cx);
                     let generics = self.generics.clean(cx);
-                    let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                     AssocTypeItem(
                         Typedef { type_, generics, item_type: Some(item_type) },
                         Vec::new(),
@@ -1125,7 +1131,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
         let tcx = cx.tcx;
         let kind = match self.kind {
             ty::AssocKind::Const => {
-                let ty = tcx.type_of(self.def_id).clean(cx);
+                let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
 
                 let provided = match self.container {
                     ty::ImplContainer(_) => true,
@@ -1272,7 +1278,11 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                     if self.defaultness.has_value() {
                         AssocTypeItem(
                             Typedef {
-                                type_: tcx.type_of(self.def_id).clean(cx),
+                                type_: clean_middle_ty(
+                                    tcx.type_of(self.def_id),
+                                    cx,
+                                    Some(self.def_id),
+                                ),
                                 generics,
                                 // FIXME: should we obtain the Type from HIR and pass it on here?
                                 item_type: None,
@@ -1286,7 +1296,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                     // FIXME: when could this happen? Associated items in inherent impls?
                     AssocTypeItem(
                         Typedef {
-                            type_: tcx.type_of(self.def_id).clean(cx),
+                            type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
                             generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
                             item_type: None,
                         },
@@ -1337,7 +1347,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             // Try to normalize `<X as Y>::T` to a type
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             if let Some(normalized_value) = normalize(cx, ty) {
-                return normalized_value.clean(cx);
+                return clean_middle_ty(normalized_value, cx, None);
             }
 
             let trait_segments = &p.segments[..p.segments.len() - 1];
@@ -1348,7 +1358,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             };
             register_res(cx, trait_.res);
             let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
-            let self_type = qself.clean(cx);
+            let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
             Type::QPath {
                 assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)),
@@ -1368,7 +1378,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             let trait_ = hir::Path { span, res, segments: &[] }.clean(cx);
             register_res(cx, trait_.res);
             let self_def_id = res.opt_def_id();
-            let self_type = qself.clean(cx);
+            let self_type = clean_ty(qself, cx);
             let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
             Type::QPath {
                 assoc: Box::new(segment.clean(cx)),
@@ -1435,9 +1445,12 @@ fn maybe_expand_private_type_alias<'tcx>(
                     _ => None,
                 });
                 if let Some(ty) = type_ {
-                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx)));
+                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
                 } else if let Some(default) = *default {
-                    substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx)));
+                    substs.insert(
+                        ty_param_def_id.to_def_id(),
+                        SubstParam::Type(clean_ty(default, cx)),
+                    );
                 }
                 indices.types += 1;
             }
@@ -1464,70 +1477,68 @@ fn maybe_expand_private_type_alias<'tcx>(
         }
     }
 
-    Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
+    Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx)))
 }
 
-impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
-        use rustc_hir::*;
-
-        match self.kind {
-            TyKind::Never => Primitive(PrimitiveType::Never),
-            TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))),
-            TyKind::Rptr(ref l, ref m) => {
-                // There are two times a `Fresh` lifetime can be created:
-                // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
-                // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
-                //    See #59286 for more information.
-                // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
-                // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
-                // there's no case where it could cause the function to fail to compile.
-                let elided =
-                    l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
-                let lifetime = if elided { None } else { Some(l.clean(cx)) };
-                BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) }
-            }
-            TyKind::Slice(ty) => Slice(Box::new(ty.clean(cx))),
-            TyKind::Array(ty, ref length) => {
-                let length = match length {
-                    hir::ArrayLen::Infer(_, _) => "_".to_string(),
-                    hir::ArrayLen::Body(anon_const) => {
-                        let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
-                        // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
-                        // as we currently do not supply the parent generics to anonymous constants
-                        // but do allow `ConstKind::Param`.
-                        //
-                        // `const_eval_poly` tries to to first substitute generic parameters which
-                        // results in an ICE while manually constructing the constant and using `eval`
-                        // does nothing for `ConstKind::Param`.
-                        let ct = ty::Const::from_anon_const(cx.tcx, def_id);
-                        let param_env = cx.tcx.param_env(def_id);
-                        print_const(cx, ct.eval(cx.tcx, param_env))
-                    }
-                };
+pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
+    use rustc_hir::*;
 
-                Array(Box::new(ty.clean(cx)), length)
-            }
-            TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
-            TyKind::OpaqueDef(item_id, _) => {
-                let item = cx.tcx.hir().item(item_id);
-                if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
-                    ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
-                } else {
-                    unreachable!()
+    match ty.kind {
+        TyKind::Never => Primitive(PrimitiveType::Never),
+        TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
+        TyKind::Rptr(ref l, ref m) => {
+            // There are two times a `Fresh` lifetime can be created:
+            // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
+            // 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
+            //    See #59286 for more information.
+            // Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
+            // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
+            // there's no case where it could cause the function to fail to compile.
+            let elided =
+                l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
+            let lifetime = if elided { None } else { Some(l.clean(cx)) };
+            BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
+        }
+        TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
+        TyKind::Array(ty, ref length) => {
+            let length = match length {
+                hir::ArrayLen::Infer(_, _) => "_".to_string(),
+                hir::ArrayLen::Body(anon_const) => {
+                    let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
+                    // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
+                    // as we currently do not supply the parent generics to anonymous constants
+                    // but do allow `ConstKind::Param`.
+                    //
+                    // `const_eval_poly` tries to to first substitute generic parameters which
+                    // results in an ICE while manually constructing the constant and using `eval`
+                    // does nothing for `ConstKind::Param`.
+                    let ct = ty::Const::from_anon_const(cx.tcx, def_id);
+                    let param_env = cx.tcx.param_env(def_id);
+                    print_const(cx, ct.eval(cx.tcx, param_env))
                 }
+            };
+
+            Array(Box::new(clean_ty(ty, cx)), length)
+        }
+        TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
+        TyKind::OpaqueDef(item_id, _) => {
+            let item = cx.tcx.hir().item(item_id);
+            if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
+                ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
+            } else {
+                unreachable!()
             }
-            TyKind::Path(_) => clean_qpath(self, cx),
-            TyKind::TraitObject(bounds, ref lifetime, _) => {
-                let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
-                let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
-                DynTrait(bounds, lifetime)
-            }
-            TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
-            // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
-            TyKind::Infer | TyKind::Err => Infer,
-            TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
         }
+        TyKind::Path(_) => clean_qpath(ty, cx),
+        TyKind::TraitObject(bounds, ref lifetime, _) => {
+            let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
+            let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
+            DynTrait(bounds, lifetime)
+        }
+        TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
+        // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
+        TyKind::Infer | TyKind::Err => Infer,
+        TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind),
     }
 }
 
@@ -1562,7 +1573,11 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
     }
 }
 
-fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefId>) -> Type {
+pub(crate) fn clean_middle_ty<'tcx>(
+    this: Ty<'tcx>,
+    cx: &mut DocContext<'tcx>,
+    def_id: Option<DefId>,
+) -> Type {
     trace!("cleaning type: {:?}", this);
     let ty = normalize(cx, this).unwrap_or(this);
     match *ty.kind() {
@@ -1573,17 +1588,19 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
         ty::Uint(uint_ty) => Primitive(uint_ty.into()),
         ty::Float(float_ty) => Primitive(float_ty.into()),
         ty::Str => Primitive(PrimitiveType::Str),
-        ty::Slice(ty) => Slice(Box::new(ty.clean(cx))),
+        ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))),
         ty::Array(ty, n) => {
             let mut n = cx.tcx.lift(n).expect("array lift failed");
             n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
-            Array(Box::new(ty.clean(cx)), n)
-        }
-        ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))),
-        ty::Ref(r, ty, mutbl) => {
-            BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: Box::new(ty.clean(cx)) }
+            Array(Box::new(clean_middle_ty(ty, cx, None)), n)
         }
+        ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
+        ty::Ref(r, ty, mutbl) => BorrowedRef {
+            lifetime: r.clean(cx),
+            mutability: mutbl,
+            type_: Box::new(clean_middle_ty(ty, cx, None)),
+        },
         ty::FnDef(..) | ty::FnPtr(_) => {
             let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
             let sig = ty.fn_sig(cx.tcx);
@@ -1660,7 +1677,7 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
 
             DynTrait(bounds, lifetime)
         }
-        ty::Tuple(t) => Tuple(t.iter().map(|t| t.clean(cx)).collect()),
+        ty::Tuple(t) => Tuple(t.iter().map(|t| clean_middle_ty(t, cx, None)).collect()),
 
         ty::Projection(ref data) => clean_projection(*data, cx, def_id),
 
@@ -1747,17 +1764,11 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
     }
 }
 
-impl<'tcx> Clean<'tcx, Type> for Ty<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
-        clean_ty(*self, cx, None)
-    }
-}
-
 impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Constant {
         // FIXME: instead of storing the stringified expression, store `self` directly instead.
         Constant {
-            type_: self.ty().clean(cx),
+            type_: clean_middle_ty(self.ty(), cx, None),
             kind: ConstantKind::TyConst { expr: self.to_string() },
         }
     }
@@ -1766,13 +1777,18 @@ impl<'tcx> Clean<'tcx, Constant> for ty::Const<'tcx> {
 impl<'tcx> Clean<'tcx, Item> for hir::FieldDef<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let def_id = cx.tcx.hir().local_def_id(self.hir_id).to_def_id();
-        clean_field(def_id, self.ident.name, self.ty.clean(cx), cx)
+        clean_field(def_id, self.ident.name, clean_ty(self.ty, cx), cx)
     }
 }
 
 impl<'tcx> Clean<'tcx, Item> for ty::FieldDef {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx)
+        clean_field(
+            self.did,
+            self.name,
+            clean_middle_ty(cx.tcx.type_of(self.did), cx, Some(self.did)),
+            cx,
+        )
     }
 }
 
@@ -1863,10 +1879,10 @@ impl<'tcx> Clean<'tcx, Path> for hir::Path<'tcx> {
 impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
         if self.parenthesized {
-            let output = self.bindings[0].ty().clean(cx);
+            let output = clean_ty(self.bindings[0].ty(), cx);
             let output =
                 if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
-            let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect::<Vec<_>>().into();
+            let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
             GenericArgs::Parenthesized { inputs, output }
         } else {
             let args = self
@@ -1877,7 +1893,7 @@ impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
                         GenericArg::Lifetime(lt.clean(cx))
                     }
                     hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                    hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
+                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
                     hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
                     hir::GenericArg::Infer(_inf) => GenericArg::Infer,
                 })
@@ -1925,10 +1941,10 @@ fn clean_maybe_renamed_item<'tcx>(
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
             ItemKind::Static(ty, mutability, body_id) => {
-                StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
+                StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
             }
             ItemKind::Const(ty, body_id) => ConstantItem(Constant {
-                type_: ty.clean(cx),
+                type_: clean_ty(ty, cx),
                 kind: ConstantKind::Local { body: body_id, def_id },
             }),
             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
@@ -1936,8 +1952,8 @@ fn clean_maybe_renamed_item<'tcx>(
                 generics: ty.generics.clean(cx),
             }),
             ItemKind::TyAlias(hir_ty, generics) => {
-                let rustdoc_ty = hir_ty.clean(cx);
-                let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+                let rustdoc_ty = clean_ty(hir_ty, cx);
+                let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                 TypedefItem(Typedef {
                     type_: rustdoc_ty,
                     generics: generics.clean(cx),
@@ -2023,9 +2039,9 @@ fn clean_impl<'tcx>(
         build_deref_target_impls(cx, &items, &mut ret);
     }
 
-    let for_ = impl_.self_ty.clean(cx);
+    let for_ = clean_ty(impl_.self_ty, cx);
     let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
-        DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
+        DefKind::TyAlias => Some(clean_middle_ty(tcx.type_of(did), cx, Some(did))),
         _ => None,
     });
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
@@ -2234,7 +2250,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
                 ForeignFunctionItem(Function { decl, generics })
             }
             hir::ForeignItemKind::Static(ty, mutability) => {
-                ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
+                ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None })
             }
             hir::ForeignItemKind::Type => ForeignTypeItem,
         };
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index fa449a21b0c..00d62b37484 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -2,8 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
-    inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
-    ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
+    clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs,
+    ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type,
+    TypeBinding, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -91,7 +92,7 @@ pub(crate) fn substs_to_args<'tcx>(
             skip_first = false;
             None
         }
-        GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
+        GenericArgKind::Type(ty) => Some(GenericArg::Type(clean_middle_ty(ty, cx, None))),
         GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))),
     }));
     ret_val
@@ -110,7 +111,7 @@ fn external_generic_args<'tcx>(
         let inputs =
             // The trait's first substitution is the one after self, if there is one.
             match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
-                ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect::<Vec<_>>().into(),
+                ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::<Vec<_>>().into(),
                 _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() },
             };
         let output = None;
diff --git a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs b/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
index 68f81808861..c42fbba7425 100644
--- a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs
+++ b/src/test/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
@@ -1,10 +1,7 @@
 // Verifies that "CFI Canonical Jump Tables" module flag is added.
 //
-// ignore-windows
 // needs-sanitizer-cfi
-// only-aarch64
-// only-x86_64
-// compile-flags: -Clto -Zsanitizer=cfi
+// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
 
 #![crate_type="lib"]
 
diff --git a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs b/src/test/codegen/sanitizer-cfi-emit-type-checks.rs
index 9ed0422ceff..082f0f121ff 100644
--- a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs
+++ b/src/test/codegen/sanitizer-cfi-emit-type-checks.rs
@@ -1,10 +1,7 @@
 // Verifies that pointer type membership tests for indirect calls are emitted.
 //
-// ignore-windows
 // needs-sanitizer-cfi
-// only-aarch64
-// only-x86_64
-// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
 
 #![crate_type="lib"]
 
diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..ece2adbdf43
--- /dev/null
+++ b/src/test/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
@@ -0,0 +1,575 @@
+// Verifies that type metadata identifiers for functions are emitted correctly.
+//
+// needs-sanitizer-cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type="lib"]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+#![allow(unused_must_use)]
+#![feature(adt_const_params, extern_types, inline_const, type_alias_impl_trait)]
+
+extern crate core;
+use core::ffi::c_void;
+use std::marker::PhantomData;
+
+// User-defined type (structure)
+pub struct Struct1<T> {
+    member1: T,
+}
+
+// User-defined type (enum)
+pub enum Enum1<T> {
+    Variant1(T),
+}
+
+// User-defined type (union)
+pub union Union1<T> {
+    member1: std::mem::ManuallyDrop<T>,
+}
+
+// Extern type
+extern {
+    pub type type1;
+}
+
+// Trait
+pub trait Trait1<T> {
+    fn foo(&self) { }
+}
+
+// Trait implementation
+impl<T> Trait1<T> for i32 {
+    fn foo(&self) { }
+}
+
+// Trait implementation
+impl<T> Trait1<T> for Struct1<T> {
+    fn foo(&self) { }
+}
+
+// impl Trait type aliases for helping with defining other types (see below)
+pub type Type1 = impl Send;
+pub type Type2 = impl Send;
+pub type Type3 = impl Send;
+pub type Type4 = impl Send;
+pub type Type5 = impl Send;
+pub type Type6 = impl Send;
+pub type Type7 = impl Send;
+pub type Type8 = impl Send;
+pub type Type9 = impl Send;
+pub type Type10 = impl Send;
+pub type Type11 = impl Send;
+
+pub fn fn1<'a>() {
+    // Closure
+    let closure1 = || { };
+    let _: Type1 = closure1;
+
+    // Constructor
+    pub struct Foo(i32);
+    let _: Type2 = Foo;
+
+    // Type in extern path
+    extern {
+        fn foo();
+    }
+    let _: Type3 = foo;
+
+    // Type in closure path
+    || {
+        pub struct Foo;
+        let _: Type4 = Foo;
+    };
+
+    // Type in const path
+    const {
+        pub struct Foo;
+        fn foo() -> Type5 { Foo }
+    };
+
+    // Type in impl path
+    impl<T> Struct1<T> {
+        fn foo(&self) { }
+    }
+    let _: Type6 = <Struct1<i32>>::foo;
+
+    // Trait method
+    let _: Type7 = <dyn Trait1<i32>>::foo;
+
+    // Trait method
+    let _: Type8 = <i32 as Trait1<i32>>::foo;
+
+    // Trait method
+    let _: Type9 = <Struct1<i32> as Trait1<i32>>::foo;
+
+    // Const generics
+    pub struct Qux<T, const N: usize>([T; N]);
+    let _: Type10 = Qux([0; 32]);
+
+    // Lifetimes/regions
+    pub struct Quux<'a>(&'a i32);
+    pub struct Quuux<'a, 'b>(&'a i32, &'b Quux<'b>);
+    let _: Type11 = Quuux;
+}
+
+// repr(transparent) user-defined type
+struct Foo(i32);
+
+#[repr(transparent)]
+pub struct Type12 {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: Foo,
+}
+
+// Self-referencing repr(transparent) user-defined type
+#[repr(transparent)]
+pub struct Type13<'a> {
+    member1: (),
+    member2: PhantomData<i32>,
+    member3: &'a Type13<'a>,
+}
+
+pub fn foo0(_: ()) { }
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]]
+pub fn foo1(_: c_void, _: ()) { }
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]]
+pub fn foo2(_: (), _: c_void, _: c_void) { }
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]]
+pub fn foo3(_: *mut c_void) { }
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]]
+pub fn foo4(_: *mut c_void, _: *mut ()) { }
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]]
+pub fn foo5(_: *mut (), _: *mut c_void, _: *mut c_void) { }
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]]
+pub fn foo6(_: *const c_void) { }
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]]
+pub fn foo7(_: *const c_void, _: *const ()) { }
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]]
+pub fn foo8(_: *const (), _: *const c_void, _: *const c_void) { }
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]]
+pub fn foo9(_: bool) { }
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]]
+pub fn foo10(_: bool, _: bool) { }
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]]
+pub fn foo11(_: bool, _: bool, _: bool) { }
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]]
+pub fn foo12(_: i8) { }
+// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]]
+pub fn foo13(_: i8, _: i8) { }
+// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]]
+pub fn foo14(_: i8, _: i8, _: i8) { }
+// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]]
+pub fn foo15(_: i16) { }
+// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]]
+pub fn foo16(_: i16, _: i16) { }
+// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]]
+pub fn foo17(_: i16, _: i16, _: i16) { }
+// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]]
+pub fn foo18(_: i32) { }
+// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]]
+pub fn foo19(_: i32, _: i32) { }
+// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]]
+pub fn foo20(_: i32, _: i32, _: i32) { }
+// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]]
+pub fn foo21(_: i64) { }
+// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]]
+pub fn foo22(_: i64, _: i64) { }
+// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]]
+pub fn foo23(_: i64, _: i64, _: i64) { }
+// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]]
+pub fn foo24(_: i128) { }
+// CHECK: define{{.*}}foo24{{.*}}!type ![[TYPE24:[0-9]+]]
+pub fn foo25(_: i128, _: i128) { }
+// CHECK: define{{.*}}foo25{{.*}}!type ![[TYPE25:[0-9]+]]
+pub fn foo26(_: i128, _: i128, _: i128) { }
+// CHECK: define{{.*}}foo26{{.*}}!type ![[TYPE26:[0-9]+]]
+pub fn foo27(_: isize) { }
+// CHECK: define{{.*}}foo27{{.*}}!type ![[TYPE27:[0-9]+]]
+pub fn foo28(_: isize, _: isize) { }
+// CHECK: define{{.*}}foo28{{.*}}!type ![[TYPE28:[0-9]+]]
+pub fn foo29(_: isize, _: isize, _: isize) { }
+// CHECK: define{{.*}}foo29{{.*}}!type ![[TYPE29:[0-9]+]]
+pub fn foo30(_: u8) { }
+// CHECK: define{{.*}}foo30{{.*}}!type ![[TYPE30:[0-9]+]]
+pub fn foo31(_: u8, _: u8) { }
+// CHECK: define{{.*}}foo31{{.*}}!type ![[TYPE31:[0-9]+]]
+pub fn foo32(_: u8, _: u8, _: u8) { }
+// CHECK: define{{.*}}foo32{{.*}}!type ![[TYPE32:[0-9]+]]
+pub fn foo33(_: u16) { }
+// CHECK: define{{.*}}foo33{{.*}}!type ![[TYPE33:[0-9]+]]
+pub fn foo34(_: u16, _: u16) { }
+// CHECK: define{{.*}}foo34{{.*}}!type ![[TYPE34:[0-9]+]]
+pub fn foo35(_: u16, _: u16, _: u16) { }
+// CHECK: define{{.*}}foo35{{.*}}!type ![[TYPE35:[0-9]+]]
+pub fn foo36(_: u32) { }
+// CHECK: define{{.*}}foo36{{.*}}!type ![[TYPE36:[0-9]+]]
+pub fn foo37(_: u32, _: u32) { }
+// CHECK: define{{.*}}foo37{{.*}}!type ![[TYPE37:[0-9]+]]
+pub fn foo38(_: u32, _: u32, _: u32) { }
+// CHECK: define{{.*}}foo38{{.*}}!type ![[TYPE38:[0-9]+]]
+pub fn foo39(_: u64) { }
+// CHECK: define{{.*}}foo39{{.*}}!type ![[TYPE39:[0-9]+]]
+pub fn foo40(_: u64, _: u64) { }
+// CHECK: define{{.*}}foo40{{.*}}!type ![[TYPE40:[0-9]+]]
+pub fn foo41(_: u64, _: u64, _: u64) { }
+// CHECK: define{{.*}}foo41{{.*}}!type ![[TYPE41:[0-9]+]]
+pub fn foo42(_: u128) { }
+// CHECK: define{{.*}}foo42{{.*}}!type ![[TYPE42:[0-9]+]]
+pub fn foo43(_: u128, _: u128) { }
+// CHECK: define{{.*}}foo43{{.*}}!type ![[TYPE43:[0-9]+]]
+pub fn foo44(_: u128, _: u128, _: u128) { }
+// CHECK: define{{.*}}foo44{{.*}}!type ![[TYPE44:[0-9]+]]
+pub fn foo45(_: usize) { }
+// CHECK: define{{.*}}foo45{{.*}}!type ![[TYPE45:[0-9]+]]
+pub fn foo46(_: usize, _: usize) { }
+// CHECK: define{{.*}}foo46{{.*}}!type ![[TYPE46:[0-9]+]]
+pub fn foo47(_: usize, _: usize, _: usize) { }
+// CHECK: define{{.*}}foo47{{.*}}!type ![[TYPE47:[0-9]+]]
+pub fn foo48(_: f32) { }
+// CHECK: define{{.*}}foo48{{.*}}!type ![[TYPE48:[0-9]+]]
+pub fn foo49(_: f32, _: f32) { }
+// CHECK: define{{.*}}foo49{{.*}}!type ![[TYPE49:[0-9]+]]
+pub fn foo50(_: f32, _: f32, _: f32) { }
+// CHECK: define{{.*}}foo50{{.*}}!type ![[TYPE50:[0-9]+]]
+pub fn foo51(_: f64) { }
+// CHECK: define{{.*}}foo51{{.*}}!type ![[TYPE51:[0-9]+]]
+pub fn foo52(_: f64, _: f64) { }
+// CHECK: define{{.*}}foo52{{.*}}!type ![[TYPE52:[0-9]+]]
+pub fn foo53(_: f64, _: f64, _: f64) { }
+// CHECK: define{{.*}}foo53{{.*}}!type ![[TYPE53:[0-9]+]]
+pub fn foo54(_: char) { }
+// CHECK: define{{.*}}foo54{{.*}}!type ![[TYPE54:[0-9]+]]
+pub fn foo55(_: char, _: char) { }
+// CHECK: define{{.*}}foo55{{.*}}!type ![[TYPE55:[0-9]+]]
+pub fn foo56(_: char, _: char, _: char) { }
+// CHECK: define{{.*}}foo56{{.*}}!type ![[TYPE56:[0-9]+]]
+pub fn foo57(_: &str) { }
+// CHECK: define{{.*}}foo57{{.*}}!type ![[TYPE57:[0-9]+]]
+pub fn foo58(_: &str, _: &str) { }
+// CHECK: define{{.*}}foo58{{.*}}!type ![[TYPE58:[0-9]+]]
+pub fn foo59(_: &str, _: &str, _: &str) { }
+// CHECK: define{{.*}}foo59{{.*}}!type ![[TYPE59:[0-9]+]]
+pub fn foo60(_: (i32, i32)) { }
+// CHECK: define{{.*}}foo60{{.*}}!type ![[TYPE60:[0-9]+]]
+pub fn foo61(_: (i32, i32), _: (i32, i32)) { }
+// CHECK: define{{.*}}foo61{{.*}}!type ![[TYPE61:[0-9]+]]
+pub fn foo62(_: (i32, i32), _: (i32, i32), _: (i32, i32)) { }
+// CHECK: define{{.*}}foo62{{.*}}!type ![[TYPE62:[0-9]+]]
+pub fn foo63(_: [i32; 32]) { }
+// CHECK: define{{.*}}foo63{{.*}}!type ![[TYPE63:[0-9]+]]
+pub fn foo64(_: [i32; 32], _: [i32; 32]) { }
+// CHECK: define{{.*}}foo64{{.*}}!type ![[TYPE64:[0-9]+]]
+pub fn foo65(_: [i32; 32], _: [i32; 32], _: [i32; 32]) { }
+// CHECK: define{{.*}}foo65{{.*}}!type ![[TYPE65:[0-9]+]]
+pub fn foo66(_: &[i32]) { }
+// CHECK: define{{.*}}foo66{{.*}}!type ![[TYPE66:[0-9]+]]
+pub fn foo67(_: &[i32], _: &[i32]) { }
+// CHECK: define{{.*}}foo67{{.*}}!type ![[TYPE67:[0-9]+]]
+pub fn foo68(_: &[i32], _: &[i32], _: &[i32]) { }
+// CHECK: define{{.*}}foo68{{.*}}!type ![[TYPE68:[0-9]+]]
+pub fn foo69(_: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo69{{.*}}!type ![[TYPE69:[0-9]+]]
+pub fn foo70(_: &Struct1::<i32>, _: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo70{{.*}}!type ![[TYPE70:[0-9]+]]
+pub fn foo71(_: &Struct1::<i32>, _: &Struct1::<i32>, _: &Struct1::<i32>) { }
+// CHECK: define{{.*}}foo71{{.*}}!type ![[TYPE71:[0-9]+]]
+pub fn foo72(_: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo72{{.*}}!type ![[TYPE72:[0-9]+]]
+pub fn foo73(_: &Enum1::<i32>, _: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo73{{.*}}!type ![[TYPE73:[0-9]+]]
+pub fn foo74(_: &Enum1::<i32>, _: &Enum1::<i32>, _: &Enum1::<i32>) { }
+// CHECK: define{{.*}}foo74{{.*}}!type ![[TYPE74:[0-9]+]]
+pub fn foo75(_: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo75{{.*}}!type ![[TYPE75:[0-9]+]]
+pub fn foo76(_: &Union1::<i32>, _: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo76{{.*}}!type ![[TYPE76:[0-9]+]]
+pub fn foo77(_: &Union1::<i32>, _: &Union1::<i32>, _: &Union1::<i32>) { }
+// CHECK: define{{.*}}foo77{{.*}}!type ![[TYPE77:[0-9]+]]
+pub fn foo78(_: *mut type1) { }
+// CHECK: define{{.*}}foo78{{.*}}!type ![[TYPE78:[0-9]+]]
+pub fn foo79(_: *mut type1, _: *mut type1) { }
+// CHECK: define{{.*}}foo79{{.*}}!type ![[TYPE79:[0-9]+]]
+pub fn foo80(_: *mut type1, _: *mut type1, _: *mut type1) { }
+// CHECK: define{{.*}}foo80{{.*}}!type ![[TYPE80:[0-9]+]]
+pub fn foo81(_: &mut i32) { }
+// CHECK: define{{.*}}foo81{{.*}}!type ![[TYPE81:[0-9]+]]
+pub fn foo82(_: &mut i32, _: &i32) { }
+// CHECK: define{{.*}}foo82{{.*}}!type ![[TYPE82:[0-9]+]]
+pub fn foo83(_: &mut i32, _: &i32, _: &i32) { }
+// CHECK: define{{.*}}foo83{{.*}}!type ![[TYPE83:[0-9]+]]
+pub fn foo84(_: &i32) { }
+// CHECK: define{{.*}}foo84{{.*}}!type ![[TYPE84:[0-9]+]]
+pub fn foo85(_: &i32, _: &mut i32) { }
+// CHECK: define{{.*}}foo85{{.*}}!type ![[TYPE85:[0-9]+]]
+pub fn foo86(_: &i32, _: &mut i32, _: &mut i32) { }
+// CHECK: define{{.*}}foo86{{.*}}!type ![[TYPE86:[0-9]+]]
+pub fn foo87(_: *mut i32) { }
+// CHECK: define{{.*}}foo87{{.*}}!type ![[TYPE87:[0-9]+]]
+pub fn foo88(_: *mut i32, _: *const i32) { }
+// CHECK: define{{.*}}foo88{{.*}}!type ![[TYPE88:[0-9]+]]
+pub fn foo89(_: *mut i32, _: *const i32, _: *const i32) { }
+// CHECK: define{{.*}}foo89{{.*}}!type ![[TYPE89:[0-9]+]]
+pub fn foo90(_: *const i32) { }
+// CHECK: define{{.*}}foo90{{.*}}!type ![[TYPE90:[0-9]+]]
+pub fn foo91(_: *const i32, _: *mut i32) { }
+// CHECK: define{{.*}}foo91{{.*}}!type ![[TYPE91:[0-9]+]]
+pub fn foo92(_: *const i32, _: *mut i32, _: *mut i32) { }
+// CHECK: define{{.*}}foo92{{.*}}!type ![[TYPE92:[0-9]+]]
+pub fn foo93(_: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo93{{.*}}!type ![[TYPE93:[0-9]+]]
+pub fn foo94(_: fn(i32) -> i32, _: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo94{{.*}}!type ![[TYPE94:[0-9]+]]
+pub fn foo95(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo95{{.*}}!type ![[TYPE95:[0-9]+]]
+pub fn foo96(_: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo96{{.*}}!type ![[TYPE96:[0-9]+]]
+pub fn foo97(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo97{{.*}}!type ![[TYPE97:[0-9]+]]
+pub fn foo98(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { }
+// CHECK: define{{.*}}foo98{{.*}}!type ![[TYPE98:[0-9]+]]
+pub fn foo99(_: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo99{{.*}}!type ![[TYPE99:[0-9]+]]
+pub fn foo100(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo100{{.*}}!type ![[TYPE100:[0-9]+]]
+pub fn foo101(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { }
+// CHECK: define{{.*}}foo101{{.*}}!type ![[TYPE101:[0-9]+]]
+pub fn foo102(_: &dyn FnOnce(i32) -> i32) { }
+// CHECK: define{{.*}}foo102{{.*}}!type ![[TYPE102:[0-9]+]]
+pub fn foo103(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { }
+// CHECK: define{{.*}}foo103{{.*}}!type ![[TYPE103:[0-9]+]]
+pub fn foo104(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {}
+// CHECK: define{{.*}}foo104{{.*}}!type ![[TYPE104:[0-9]+]]
+pub fn foo105(_: &dyn Send) { }
+// CHECK: define{{.*}}foo105{{.*}}!type ![[TYPE105:[0-9]+]]
+pub fn foo106(_: &dyn Send, _: &dyn Send) { }
+// CHECK: define{{.*}}foo106{{.*}}!type ![[TYPE106:[0-9]+]]
+pub fn foo107(_: &dyn Send, _: &dyn Send, _: &dyn Send) { }
+// CHECK: define{{.*}}foo107{{.*}}!type ![[TYPE107:[0-9]+]]
+pub fn foo108(_: Type1) { }
+// CHECK: define{{.*}}foo108{{.*}}!type ![[TYPE108:[0-9]+]]
+pub fn foo109(_: Type1, _: Type1) { }
+// CHECK: define{{.*}}foo109{{.*}}!type ![[TYPE109:[0-9]+]]
+pub fn foo110(_: Type1, _: Type1, _: Type1) { }
+// CHECK: define{{.*}}foo110{{.*}}!type ![[TYPE110:[0-9]+]]
+pub fn foo111(_: Type2) { }
+// CHECK: define{{.*}}foo111{{.*}}!type ![[TYPE111:[0-9]+]]
+pub fn foo112(_: Type2, _: Type2) { }
+// CHECK: define{{.*}}foo112{{.*}}!type ![[TYPE112:[0-9]+]]
+pub fn foo113(_: Type2, _: Type2, _: Type2) { }
+// CHECK: define{{.*}}foo113{{.*}}!type ![[TYPE113:[0-9]+]]
+pub fn foo114(_: Type3) { }
+// CHECK: define{{.*}}foo114{{.*}}!type ![[TYPE114:[0-9]+]]
+pub fn foo115(_: Type3, _: Type3) { }
+// CHECK: define{{.*}}foo115{{.*}}!type ![[TYPE115:[0-9]+]]
+pub fn foo116(_: Type3, _: Type3, _: Type3) { }
+// CHECK: define{{.*}}foo116{{.*}}!type ![[TYPE116:[0-9]+]]
+pub fn foo117(_: Type4) { }
+// CHECK: define{{.*}}foo117{{.*}}!type ![[TYPE117:[0-9]+]]
+pub fn foo118(_: Type4, _: Type4) { }
+// CHECK: define{{.*}}foo118{{.*}}!type ![[TYPE118:[0-9]+]]
+pub fn foo119(_: Type4, _: Type4, _: Type4) { }
+// CHECK: define{{.*}}foo119{{.*}}!type ![[TYPE119:[0-9]+]]
+pub fn foo120(_: Type5) { }
+// CHECK: define{{.*}}foo120{{.*}}!type ![[TYPE120:[0-9]+]]
+pub fn foo121(_: Type5, _: Type5) { }
+// CHECK: define{{.*}}foo121{{.*}}!type ![[TYPE121:[0-9]+]]
+pub fn foo122(_: Type5, _: Type5, _: Type5) { }
+// CHECK: define{{.*}}foo122{{.*}}!type ![[TYPE122:[0-9]+]]
+pub fn foo123(_: Type6) { }
+// CHECK: define{{.*}}foo123{{.*}}!type ![[TYPE123:[0-9]+]]
+pub fn foo124(_: Type6, _: Type6) { }
+// CHECK: define{{.*}}foo124{{.*}}!type ![[TYPE124:[0-9]+]]
+pub fn foo125(_: Type6, _: Type6, _: Type6) { }
+// CHECK: define{{.*}}foo125{{.*}}!type ![[TYPE125:[0-9]+]]
+pub fn foo126(_: Type7) { }
+// CHECK: define{{.*}}foo126{{.*}}!type ![[TYPE126:[0-9]+]]
+pub fn foo127(_: Type7, _: Type7) { }
+// CHECK: define{{.*}}foo127{{.*}}!type ![[TYPE127:[0-9]+]]
+pub fn foo128(_: Type7, _: Type7, _: Type7) { }
+// CHECK: define{{.*}}foo128{{.*}}!type ![[TYPE128:[0-9]+]]
+pub fn foo129(_: Type8) { }
+// CHECK: define{{.*}}foo129{{.*}}!type ![[TYPE129:[0-9]+]]
+pub fn foo130(_: Type8, _: Type8) { }
+// CHECK: define{{.*}}foo130{{.*}}!type ![[TYPE130:[0-9]+]]
+pub fn foo131(_: Type8, _: Type8, _: Type8) { }
+// CHECK: define{{.*}}foo131{{.*}}!type ![[TYPE131:[0-9]+]]
+pub fn foo132(_: Type9) { }
+// CHECK: define{{.*}}foo132{{.*}}!type ![[TYPE132:[0-9]+]]
+pub fn foo133(_: Type9, _: Type9) { }
+// CHECK: define{{.*}}foo133{{.*}}!type ![[TYPE133:[0-9]+]]
+pub fn foo134(_: Type9, _: Type9, _: Type9) { }
+// CHECK: define{{.*}}foo134{{.*}}!type ![[TYPE134:[0-9]+]]
+pub fn foo135(_: Type10) { }
+// CHECK: define{{.*}}foo135{{.*}}!type ![[TYPE135:[0-9]+]]
+pub fn foo136(_: Type10, _: Type10) { }
+// CHECK: define{{.*}}foo136{{.*}}!type ![[TYPE136:[0-9]+]]
+pub fn foo137(_: Type10, _: Type10, _: Type10) { }
+// CHECK: define{{.*}}foo137{{.*}}!type ![[TYPE137:[0-9]+]]
+pub fn foo138(_: Type11) { }
+// CHECK: define{{.*}}foo138{{.*}}!type ![[TYPE138:[0-9]+]]
+pub fn foo139(_: Type11, _: Type11) { }
+// CHECK: define{{.*}}foo139{{.*}}!type ![[TYPE139:[0-9]+]]
+pub fn foo140(_: Type11, _: Type11, _: Type11) { }
+// CHECK: define{{.*}}foo140{{.*}}!type ![[TYPE140:[0-9]+]]
+pub fn foo141(_: Type12) { }
+// CHECK: define{{.*}}foo141{{.*}}!type ![[TYPE141:[0-9]+]]
+pub fn foo142(_: Type12, _: Type12) { }
+// CHECK: define{{.*}}foo142{{.*}}!type ![[TYPE142:[0-9]+]]
+pub fn foo143(_: Type12, _: Type12, _: Type12) { }
+// CHECK: define{{.*}}foo143{{.*}}!type ![[TYPE143:[0-9]+]]
+pub fn foo144(_: Type13) { }
+// CHECK: define{{.*}}foo144{{.*}}!type ![[TYPE144:[0-9]+]]
+pub fn foo145(_: Type13, _: Type13) { }
+// CHECK: define{{.*}}foo145{{.*}}!type ![[TYPE145:[0-9]+]]
+pub fn foo146(_: Type13, _: Type13, _: Type13) { }
+// CHECK: define{{.*}}foo146{{.*}}!type ![[TYPE146:[0-9]+]]
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvvE"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvvE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvvE"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPvE"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvS_E"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_S_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPKvE"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvPKvS0_E"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvPKvS0_S0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvbE"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvbbE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvbbbE"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2i8E"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2i8S_E"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2i8S_S_E"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3i32E"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3i32S_E"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3i32S_S_E"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3i64E"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3i64S_E"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3i64S_S_E"}
+// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu4i128E"}
+// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu4i128S_E"}
+// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu4i128S_S_E"}
+// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu5isizeE"}
+// CHECK: ![[TYPE28]] = !{i64 0, !"_ZTSFvu5isizeS_E"}
+// CHECK: ![[TYPE29]] = !{i64 0, !"_ZTSFvu5isizeS_S_E"}
+// CHECK: ![[TYPE30]] = !{i64 0, !"_ZTSFvu2u8E"}
+// CHECK: ![[TYPE31]] = !{i64 0, !"_ZTSFvu2u8S_E"}
+// CHECK: ![[TYPE32]] = !{i64 0, !"_ZTSFvu2u8S_S_E"}
+// CHECK: ![[TYPE33]] = !{i64 0, !"_ZTSFvu3u16E"}
+// CHECK: ![[TYPE34]] = !{i64 0, !"_ZTSFvu3u16S_E"}
+// CHECK: ![[TYPE35]] = !{i64 0, !"_ZTSFvu3u16S_S_E"}
+// CHECK: ![[TYPE36]] = !{i64 0, !"_ZTSFvu3u32E"}
+// CHECK: ![[TYPE37]] = !{i64 0, !"_ZTSFvu3u32S_E"}
+// CHECK: ![[TYPE38]] = !{i64 0, !"_ZTSFvu3u32S_S_E"}
+// CHECK: ![[TYPE39]] = !{i64 0, !"_ZTSFvu3u64E"}
+// CHECK: ![[TYPE40]] = !{i64 0, !"_ZTSFvu3u64S_E"}
+// CHECK: ![[TYPE41]] = !{i64 0, !"_ZTSFvu3u64S_S_E"}
+// CHECK: ![[TYPE42]] = !{i64 0, !"_ZTSFvu4u128E"}
+// CHECK: ![[TYPE43]] = !{i64 0, !"_ZTSFvu4u128S_E"}
+// CHECK: ![[TYPE44]] = !{i64 0, !"_ZTSFvu4u128S_S_E"}
+// CHECK: ![[TYPE45]] = !{i64 0, !"_ZTSFvu5usizeE"}
+// CHECK: ![[TYPE46]] = !{i64 0, !"_ZTSFvu5usizeS_E"}
+// CHECK: ![[TYPE47]] = !{i64 0, !"_ZTSFvu5usizeS_S_E"}
+// CHECK: ![[TYPE48]] = !{i64 0, !"_ZTSFvu3f32E"}
+// CHECK: ![[TYPE49]] = !{i64 0, !"_ZTSFvu3f32S_E"}
+// CHECK: ![[TYPE50]] = !{i64 0, !"_ZTSFvu3f32S_S_E"}
+// CHECK: ![[TYPE51]] = !{i64 0, !"_ZTSFvu3f64E"}
+// CHECK: ![[TYPE52]] = !{i64 0, !"_ZTSFvu3f64S_E"}
+// CHECK: ![[TYPE53]] = !{i64 0, !"_ZTSFvu3f64S_S_E"}
+// CHECK: ![[TYPE54]] = !{i64 0, !"_ZTSFvu4charE"}
+// CHECK: ![[TYPE55]] = !{i64 0, !"_ZTSFvu4charS_E"}
+// CHECK: ![[TYPE56]] = !{i64 0, !"_ZTSFvu4charS_S_E"}
+// CHECK: ![[TYPE57]] = !{i64 0, !"_ZTSFvu3refIu3strEE"}
+// CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"}
+// CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"}
+// CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_EE"}
+// CHECK: ![[TYPE61]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_E"}
+// CHECK: ![[TYPE62]] = !{i64 0, !"_ZTSFvu5tupleIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE63]] = !{i64 0, !"_ZTSFvA32u3i32E"}
+// CHECK: ![[TYPE64]] = !{i64 0, !"_ZTSFvA32u3i32S0_E"}
+// CHECK: ![[TYPE65]] = !{i64 0, !"_ZTSFvA32u3i32S0_S0_E"}
+// CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"}
+// CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"}
+// CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"}
+// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"}
+// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"}
+// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"}
+// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"}
+// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"}
+// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"}
+// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"}
+// CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"}
+// CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"}
+// CHECK: ![[TYPE81]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32EE"}
+// CHECK: ![[TYPE82]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_E"}
+// CHECK: ![[TYPE83]] = !{i64 0, !"_ZTSFvU3mutu3refIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE84]] = !{i64 0, !"_ZTSFvu3refIu3i32EE"}
+// CHECK: ![[TYPE85]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_E"}
+// CHECK: ![[TYPE86]] = !{i64 0, !"_ZTSFvu3refIu3i32EU3mutS0_S1_E"}
+// CHECK: ![[TYPE87]] = !{i64 0, !"_ZTSFvPu3i32E"}
+// CHECK: ![[TYPE88]] = !{i64 0, !"_ZTSFvPu3i32PKS_E"}
+// CHECK: ![[TYPE89]] = !{i64 0, !"_ZTSFvPu3i32PKS_S2_E"}
+// CHECK: ![[TYPE90]] = !{i64 0, !"_ZTSFvPKu3i32E"}
+// CHECK: ![[TYPE91]] = !{i64 0, !"_ZTSFvPKu3i32PS_E"}
+// CHECK: ![[TYPE92]] = !{i64 0, !"_ZTSFvPKu3i32PS_S2_E"}
+// CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"}
+// CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"}
+// CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"}
+// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"}
+// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"}
+// CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
+// CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"}
+// CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"}
+// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"}
+// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"}
+// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"}
+// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"}
+// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"}
+// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"}
+// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"}
+// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"}
+// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"}
+// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"}
+// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"}
+// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"}
+// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"}
+// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"}
+// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"}
+// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"}
+// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"}
+// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"}
+// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"}
+// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"}
+// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"}
+// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"}
+// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"}
+// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"}
+// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"}
+// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"}
+// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"}
+// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"}
+// CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIu3refIvEEE"}
+// CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_E"}
+// CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIu3refIvEES0_S0_E"}
diff --git a/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
new file mode 100644
index 00000000000..09310ba9f60
--- /dev/null
+++ b/src/test/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
@@ -0,0 +1,31 @@
+// Verifies that type metadata for functions are emitted.
+//
+// needs-sanitizer-cfi
+// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]]
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_E")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]]
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_S_E")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]]
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"_ZTSFu3i32S_S_S_E")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFu3i32PFS_S_ES_E"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_ES_S_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFu3i32PFS_S_S_S_ES_S_S_E"}
diff --git a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs b/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs
deleted file mode 100644
index 96fced47e78..00000000000
--- a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Verifies that type metadata for functions are emitted.
-//
-// ignore-windows
-// needs-sanitizer-cfi
-// only-aarch64
-// only-x86_64
-// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
-
-#![crate_type="lib"]
-
-pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
-    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
-    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1")
-    f(arg)
-}
-
-pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
-    // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}}
-    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2")
-    f(arg1, arg2)
-}
-
-pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
-    // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}}
-    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3")
-    f(arg1, arg2, arg3)
-}
-
-// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"}
-// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"}
-// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"}
diff --git a/src/test/codegen/sanitizer_scs_attr_check.rs b/src/test/codegen/sanitizer_scs_attr_check.rs
new file mode 100644
index 00000000000..0b53db3b767
--- /dev/null
+++ b/src/test/codegen/sanitizer_scs_attr_check.rs
@@ -0,0 +1,17 @@
+// This tests that the shadowcallstack attribute is
+// applied when enabling the shadow-call-stack sanitizer.
+//
+// needs-sanitizer-shadow-call-stack
+// compile-flags: -Zsanitizer=shadow-call-stack
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+// CHECK-NEXT: scs
+pub fn scs() {}
+
+// CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
+// CHECK-NEXT: no_scs
+#[no_sanitize(shadow_call_stack)]
+pub fn no_scs() {}
diff --git a/src/test/ui-fulldeps/gated-plugin.rs b/src/test/ui-fulldeps/gated-plugin.rs
index 445469f8733..85eaf533643 100644
--- a/src/test/ui-fulldeps/gated-plugin.rs
+++ b/src/test/ui-fulldeps/gated-plugin.rs
@@ -1,4 +1,5 @@
 // aux-build:empty-plugin.rs
+// ignore-stage1
 
 #![plugin(empty_plugin)]
 //~^ ERROR compiler plugins are deprecated
diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr
index b8b7dd23c1c..f48f1eab60b 100644
--- a/src/test/ui-fulldeps/gated-plugin.stderr
+++ b/src/test/ui-fulldeps/gated-plugin.stderr
@@ -1,5 +1,5 @@
 error[E0658]: compiler plugins are deprecated
-  --> $DIR/gated-plugin.rs:3:1
+  --> $DIR/gated-plugin.rs:4:1
    |
 LL | #![plugin(empty_plugin)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![plugin(empty_plugin)]
    = help: add `#![feature(plugin)]` to the crate attributes to enable
 
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/gated-plugin.rs:3:1
+  --> $DIR/gated-plugin.rs:4:1
    |
 LL | #![plugin(empty_plugin)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
diff --git a/src/test/ui-fulldeps/multiple-plugins.rs b/src/test/ui-fulldeps/multiple-plugins.rs
index 25d2c8bc123..9af3ebd570c 100644
--- a/src/test/ui-fulldeps/multiple-plugins.rs
+++ b/src/test/ui-fulldeps/multiple-plugins.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:multiple-plugins-1.rs
 // aux-build:multiple-plugins-2.rs
+// ignore-stage1
 
 // Check that the plugin registrar of multiple plugins doesn't conflict
 
diff --git a/src/test/ui-fulldeps/multiple-plugins.stderr b/src/test/ui-fulldeps/multiple-plugins.stderr
index 99151933c4b..878ffabfc7f 100644
--- a/src/test/ui-fulldeps/multiple-plugins.stderr
+++ b/src/test/ui-fulldeps/multiple-plugins.stderr
@@ -1,5 +1,5 @@
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/multiple-plugins.rs:8:1
+  --> $DIR/multiple-plugins.rs:9:1
    |
 LL | #![plugin(multiple_plugins_1)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
@@ -7,7 +7,7 @@ LL | #![plugin(multiple_plugins_1)]
    = note: `#[warn(deprecated)]` on by default
 
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/multiple-plugins.rs:9:1
+  --> $DIR/multiple-plugins.rs:10:1
    |
 LL | #![plugin(multiple_plugins_2)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
diff --git a/src/test/ui/argument-suggestions/issue-98894.rs b/src/test/ui/argument-suggestions/issue-98894.rs
new file mode 100644
index 00000000000..c2618a96716
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98894.rs
@@ -0,0 +1,4 @@
+fn main() {
+    (|_, ()| ())(if true {} else {return;});
+    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-98894.stderr b/src/test/ui/argument-suggestions/issue-98894.stderr
new file mode 100644
index 00000000000..0c8b94901e1
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98894.stderr
@@ -0,0 +1,19 @@
+error[E0057]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/issue-98894.rs:2:5
+   |
+LL |     (|_, ()| ())(if true {} else {return;});
+   |     ^^^^^^^^^^^^--------------------------- an argument of type `()` is missing
+   |
+note: closure defined here
+  --> $DIR/issue-98894.rs:2:6
+   |
+LL |     (|_, ()| ())(if true {} else {return;});
+   |      ^^^^^^^
+help: provide the argument
+   |
+LL |     (|_, ()| ())(if true {} else {return;}, ());
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
diff --git a/src/test/ui/argument-suggestions/issue-98897.rs b/src/test/ui/argument-suggestions/issue-98897.rs
new file mode 100644
index 00000000000..c55f495d698
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98897.rs
@@ -0,0 +1,4 @@
+fn main() {
+    (|_, ()| ())([return, ()]);
+    //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-98897.stderr b/src/test/ui/argument-suggestions/issue-98897.stderr
new file mode 100644
index 00000000000..8f0d98d09e8
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-98897.stderr
@@ -0,0 +1,19 @@
+error[E0057]: this function takes 2 arguments but 1 argument was supplied
+  --> $DIR/issue-98897.rs:2:5
+   |
+LL |     (|_, ()| ())([return, ()]);
+   |     ^^^^^^^^^^^^-------------- an argument of type `()` is missing
+   |
+note: closure defined here
+  --> $DIR/issue-98897.rs:2:6
+   |
+LL |     (|_, ()| ())([return, ()]);
+   |      ^^^^^^^
+help: provide the argument
+   |
+LL |     (|_, ()| ())([return, ()], ());
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
diff --git a/src/test/ui/closures/issue-99565.rs b/src/test/ui/closures/issue-99565.rs
new file mode 100644
index 00000000000..3a30d2ee034
--- /dev/null
+++ b/src/test/ui/closures/issue-99565.rs
@@ -0,0 +1,7 @@
+#![crate_type = "lib"]
+
+fn foo<T, U>(_: U) {}
+
+fn bar() {
+    foo(|| {}); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/closures/issue-99565.stderr b/src/test/ui/closures/issue-99565.stderr
new file mode 100644
index 00000000000..0d940aa9a2f
--- /dev/null
+++ b/src/test/ui/closures/issue-99565.stderr
@@ -0,0 +1,14 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-99565.rs:6:5
+   |
+LL |     foo(|| {});
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     foo::<T, _>(|| {});
+   |        ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs
index 4a6ffd1f300..b024decd4e1 100644
--- a/src/test/ui/const-generics/issues/issue-86530.rs
+++ b/src/test/ui/const-generics/issues/issue-86530.rs
@@ -15,7 +15,6 @@ where
 fn unit_literals() {
     z(" ");
     //~^ ERROR: the trait bound `&str: X` is not satisfied
-    //~| ERROR: unconstrained generic constant
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr
index c688f838dab..c63857b2314 100644
--- a/src/test/ui/const-generics/issues/issue-86530.stderr
+++ b/src/test/ui/const-generics/issues/issue-86530.stderr
@@ -15,22 +15,6 @@ LL | where
 LL |     T: X,
    |        ^ required by this bound in `z`
 
-error: unconstrained generic constant
-  --> $DIR/issue-86530.rs:16:5
-   |
-LL |     z(" ");
-   |     ^
-   |
-   = help: try adding a `where` bound using this expression: `where [(); T::Y]:`
-note: required by a bound in `z`
-  --> $DIR/issue-86530.rs:11:10
-   |
-LL | fn z<T>(t: T)
-   |    - required by a bound in this
-...
-LL |     [(); T::Y]: ,
-   |          ^^^^ required by this bound in `z`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-98629.rs b/src/test/ui/const-generics/issues/issue-98629.rs
new file mode 100644
index 00000000000..fc8666bbcdb
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-98629.rs
@@ -0,0 +1,15 @@
+#![feature(const_trait_impl)]
+
+trait Trait {
+    const N: usize;
+}
+
+impl const Trait for i32 {}
+//~^ ERROR not all trait items implemented, missing: `N`
+
+fn f()
+where
+    [(); <i32 as Trait>::N]:,
+{}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-98629.stderr b/src/test/ui/const-generics/issues/issue-98629.stderr
new file mode 100644
index 00000000000..53570220882
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-98629.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `N`
+  --> $DIR/issue-98629.rs:7:1
+   |
+LL |     const N: usize;
+   |     -------------- `N` from trait
+...
+LL | impl const Trait for i32 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `N` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr
index 5a92555eb32..d328cafa00b 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`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`
+   = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr
index 7b9a1634a0d..6592b76a39f 100644
--- a/src/test/ui/issues/issue-23041.stderr
+++ b/src/test/ui/issues/issue-23041.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed
 LL |     b.downcast_ref::<fn(_)->_>();
    |       ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
    |
-help: consider specifying the generic arguments
+help: consider specifying the generic argument
    |
 LL |     b.downcast_ref::<fn(_) -> _>();
    |                   ~~~~~~~~~~~~~~
diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr
index 863993f4509..995dce552e3 100644
--- a/src/test/ui/issues/issue-24013.stderr
+++ b/src/test/ui/issues/issue-24013.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed
 LL |     unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
    |             ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
    |
-help: consider specifying the generic arguments
+help: consider specifying the generic argument
    |
 LL |     unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
    |                 ~~~~~~~~~~
diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs
index 1d5d5930731..966d76d148a 100644
--- a/src/test/ui/issues/issue-77919.rs
+++ b/src/test/ui/issues/issue-77919.rs
@@ -1,6 +1,5 @@
 fn main() {
     [1; <Multiply<Five, Five>>::VAL];
-    //~^ ERROR: constant expression depends on a generic parameter
 }
 trait TypeVal<T> {
     const VAL: T;
diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr
index b4c877a2d74..ca256847b1f 100644
--- a/src/test/ui/issues/issue-77919.stderr
+++ b/src/test/ui/issues/issue-77919.stderr
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `PhantomData` in this scope
-  --> $DIR/issue-77919.rs:10:9
+  --> $DIR/issue-77919.rs:9:9
    |
 LL |     _n: PhantomData,
    |         ^^^^^^^^^^^ not found in this scope
@@ -10,7 +10,7 @@ LL | use std::marker::PhantomData;
    |
 
 error[E0412]: cannot find type `VAL` in this scope
-  --> $DIR/issue-77919.rs:12:63
+  --> $DIR/issue-77919.rs:11:63
    |
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          -                                                    ^^^ not found in this scope
@@ -18,7 +18,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          help: you might be missing a type parameter: `, VAL`
 
 error[E0046]: not all trait items implemented, missing: `VAL`
-  --> $DIR/issue-77919.rs:12:1
+  --> $DIR/issue-77919.rs:11:1
    |
 LL |     const VAL: T;
    |     ------------ `VAL` from trait
@@ -26,15 +26,7 @@ LL |     const VAL: T;
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-77919.rs:2:9
-   |
-LL |     [1; <Multiply<Five, Five>>::VAL];
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0046, E0412.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs
new file mode 100644
index 00000000000..7b38c15afc2
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs
@@ -0,0 +1,14 @@
+#![feature(const_trait_impl)]
+
+trait Foo {
+    fn a(&self);
+}
+trait Bar: ~const Foo {}
+
+const fn foo<T: Bar>(x: &T) {
+    x.a();
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr
new file mode 100644
index 00000000000..1766cdbee8a
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
+  --> $DIR/super-traits-fail-2.rs:9:7
+   |
+LL |     x.a();
+   |       ^^^ the trait `~const Foo` is not implemented for `T`
+   |
+note: the trait `Foo` is implemented for `T`, but that implementation is not `const`
+  --> $DIR/super-traits-fail-2.rs:9:7
+   |
+LL |     x.a();
+   |       ^^^
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-2.rs:9:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs
new file mode 100644
index 00000000000..af465cad3d2
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs
@@ -0,0 +1,16 @@
+#![feature(const_trait_impl)]
+
+trait Foo {
+    fn a(&self);
+}
+trait Bar: ~const Foo {}
+
+struct S;
+impl Foo for S {
+    fn a(&self) {}
+}
+
+impl const Bar for S {}
+//~^ ERROR the trait bound
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
new file mode 100644
index 00000000000..9e8b8f8c6ba
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `S: ~const Foo` is not satisfied
+  --> $DIR/super-traits-fail.rs:13:12
+   |
+LL | impl const Bar for S {}
+   |            ^^^ the trait `~const Foo` is not implemented for `S`
+   |
+note: the trait `Foo` is implemented for `S`, but that implementation is not `const`
+  --> $DIR/super-traits-fail.rs:13:12
+   |
+LL | impl const Bar for S {}
+   |            ^^^
+note: required by a bound in `Bar`
+  --> $DIR/super-traits-fail.rs:6:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^^^^^ required by this bound in `Bar`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | impl const Bar for S where S: ~const Foo {}
+   |                      +++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs
new file mode 100644
index 00000000000..aded4ca9a99
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs
@@ -0,0 +1,22 @@
+// check-pass
+#![feature(const_trait_impl)]
+
+trait Foo {
+    fn a(&self);
+}
+trait Bar: ~const Foo {}
+
+struct S;
+impl const Foo for S {
+    fn a(&self) {}
+}
+
+impl const Bar for S {}
+
+const fn foo<T: ~const Bar>(t: &T) {
+    t.a();
+}
+
+const _: () = foo(&S);
+
+fn main() {}
diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml
index 352a8555614..758b1b139ad 100644
--- a/src/tools/bump-stage0/Cargo.toml
+++ b/src/tools/bump-stage0/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 [dependencies]
 anyhow = "1.0.34"
 curl = "0.4.38"
-indexmap = { version = "1.7.0", features = ["serde"] }
+indexmap = { version = "1.9.1", features = ["serde"] }
 serde = { version = "1.0.125", features = ["derive"] }
 serde_json = { version = "1.0.59", features = ["preserve_order"] }
 toml = "0.5.7"
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index a1e37e7317b..638e4a54849 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -30,15 +30,7 @@ LL |     const VAL: T;
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
-error: constant expression depends on a generic parameter
-  --> $DIR/ice-6252.rs:13:9
-   |
-LL |     [1; <Multiply<Five, Five>>::VAL];
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0046, E0412.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 02f4d29a2f0..f8f193ddf83 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -871,11 +871,13 @@ pub fn make_test_description<R: Read>(
     let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
     let has_asm_support = util::has_asm_support(&config.target);
     let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+    let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
     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);
     let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
+    let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target);
     // for `-Z gcc-ld=lld`
     let has_rust_lld = config
         .compile_lib_path
@@ -908,11 +910,14 @@ pub fn make_test_description<R: Read>(
         ignore |= !rustc_has_sanitizer_support
             && config.parse_name_directive(ln, "needs-sanitizer-support");
         ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address");
+        ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi");
         ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak");
         ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory");
         ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread");
         ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress");
         ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag");
+        ignore |= !has_shadow_call_stack
+            && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack");
         ignore |= config.target_panic == PanicStrategy::Abort
             && config.parse_name_directive(ln, "needs-unwind");
         ignore |= config.target == "wasm32-unknown-unknown"
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 215af347f17..22df18ee9fb 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -96,6 +96,23 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "x86_64-unknown-linux-gnu",
 ];
 
+// FIXME(rcvalle): More targets are likely supported.
+pub const CFI_SUPPORTED_TARGETS: &[&str] = &[
+    "aarch64-apple-darwin",
+    "aarch64-fuchsia",
+    "aarch64-linux-android",
+    "aarch64-unknown-freebsd",
+    "aarch64-unknown-linux-gnu",
+    "x86_64-apple-darwin",
+    "x86_64-fuchsia",
+    "x86_64-pc-solaris",
+    "x86_64-unknown-freebsd",
+    "x86_64-unknown-illumos",
+    "x86_64-unknown-linux-gnu",
+    "x86_64-unknown-linux-musl",
+    "x86_64-unknown-netbsd",
+];
+
 pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
     // FIXME: currently broken, see #88132
     // "aarch64-apple-darwin",
@@ -121,6 +138,8 @@ pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
 pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
     &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
 
+pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
+
 const BIG_ENDIAN: &[&str] = &[
     "aarch64_be",
     "armebv7r",
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index bd08e0ede0b..33c05180408 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -9,6 +9,6 @@ clap = "3.1.1"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
-version = "0.4.18"
+version = "0.4.21"
 default-features = false
 features = ["search"]