about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/cmdline_attrs.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs39
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs174
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs85
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs60
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs27
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_data_structures/src/graph/scc/tests.rs6
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/tests.rs6
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs72
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs15
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/config.rs69
-rw-r--r--compiler/rustc_expand/src/expand.rs16
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_fs_util/src/lib.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs46
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs20
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs8
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs20
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs4
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs5
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs28
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs4
-rw-r--r--compiler/rustc_infer/src/traits/util.rs2
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/passes.rs66
-rw-r--r--compiler/rustc_interface/src/queries.rs43
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/early.rs10
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs8
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs21
-rw-r--r--compiler/rustc_lint/src/reexports.rs82
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs49
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs10
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/locator.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs23
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs3
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs7
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs37
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs45
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs5
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs26
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs56
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs9
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs26
-rw-r--r--compiler/rustc_plugin_impl/src/load.rs6
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs48
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs42
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs68
-rw-r--r--compiler/rustc_resolve/src/imports.rs32
-rw-r--r--compiler/rustc_resolve/src/lib.rs26
-rw-r--r--compiler/rustc_resolve/src/macros.rs4
-rw-r--r--compiler/rustc_session/src/filesearch.rs5
-rw-r--r--compiler/rustc_session/src/options.rs19
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--compiler/rustc_session/src/utils.rs3
-rw-r--r--compiler/rustc_target/Cargo.toml1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonical/mod.rs22
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs44
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs16
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs120
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs6
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs8
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs4
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs2
-rw-r--r--compiler/rustc_type_ir/src/lib.rs22
-rw-r--r--library/alloc/src/rc.rs6
-rw-r--r--library/alloc/src/sync.rs23
-rw-r--r--library/core/src/intrinsics/mir.rs8
-rw-r--r--library/core/src/panicking.rs3
-rw-r--r--library/std/src/io/error.rs12
-rw-r--r--library/std/src/sync/mutex.rs24
-rw-r--r--library/std/src/sys/hermit/fs.rs2
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile1
-rw-r--r--src/doc/rustdoc/src/how-to-read-rustdoc.md17
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/clean/types.rs18
-rw-r--r--src/librustdoc/formats/cache.rs4
-rw-r--r--src/librustdoc/html/static/js/search.js164
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs5
-rw-r--r--src/tools/compiletest/src/header.rs15
-rw-r--r--src/tools/lint-docs/src/lib.rs95
-rw-r--r--src/tools/miri/tests/fail/never_transmute_humans.rs2
-rw-r--r--src/tools/miri/tests/fail/never_transmute_humans.stderr4
-rw-r--r--src/tools/miri/tests/fail/never_transmute_void.rs6
-rw-r--r--src/tools/rustdoc-js/tester.js11
-rw-r--r--tests/assembly/is_aligned.rs1
-rw-r--r--tests/assembly/strict_provenance.rs1
-rw-r--r--tests/assembly/x86_64-floating-point-clamp.rs1
-rw-r--r--tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs2
-rw-r--r--tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs17
-rw-r--r--tests/assembly/x86_64-no-jump-tables.rs1
-rw-r--r--tests/codegen/intrinsics/transmute.rs196
-rw-r--r--tests/codegen/transmute-scalar.rs41
-rw-r--r--tests/mir-opt/building/shifts.rs20
-rw-r--r--tests/mir-opt/building/shifts.shift_signed.built.after.mir147
-rw-r--r--tests/mir-opt/building/shifts.shift_unsigned.built.after.mir135
-rw-r--r--tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff15
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff14
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff14
-rw-r--r--tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff23
-rw-r--r--tests/mir-opt/const_prop/transmute.rs61
-rw-r--r--tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff22
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff23
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff25
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff27
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff23
-rw-r--r--tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff15
-rw-r--r--tests/mir-opt/issue_101973.inner.ConstProp.diff28
-rw-r--r--tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff48
-rw-r--r--tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff14
-rw-r--r--tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff4
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.rs33
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff27
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff27
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff29
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff29
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff29
-rw-r--r--tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff22
-rw-r--r--tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff6
-rw-r--r--tests/run-make/issue-36710/Makefile1
-rw-r--r--tests/run-make/raw-dylib-cross-compilation/Makefile22
-rw-r--r--tests/run-make/raw-dylib-cross-compilation/lib.rs20
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks5
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks22
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks1
-rw-r--r--tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh35
-rw-r--r--tests/rustdoc-js-std/parser-errors.js58
-rw-r--r--tests/rustdoc-js-std/parser-filter.js96
-rw-r--r--tests/rustdoc-js-std/parser-generics.js6
-rw-r--r--tests/rustdoc-js-std/parser-ident.js10
-rw-r--r--tests/rustdoc-js-std/parser-literal.js2
-rw-r--r--tests/rustdoc-js-std/parser-paths.js10
-rw-r--r--tests/rustdoc-js-std/parser-quote.js9
-rw-r--r--tests/rustdoc-js-std/parser-returned.js11
-rw-r--r--tests/rustdoc-js-std/parser-separators.js18
-rw-r--r--tests/rustdoc-js-std/parser-weird-queries.js17
-rw-r--r--tests/rustdoc-js/generics-impl.js13
-rw-r--r--tests/rustdoc-js/generics.js16
-rw-r--r--tests/rustdoc-js/primitive.js10
-rw-r--r--tests/rustdoc-ui/z-help.stdout1
-rw-r--r--tests/ui/cfg/auxiliary/cfg_false_lib.rs6
-rw-r--r--tests/ui/cfg/cfg-false-feature.rs20
-rw-r--r--tests/ui/cfg/cfg-false-feature.stderr35
-rw-r--r--tests/ui/cfg/cfg_false_no_std.rs11
-rw-r--r--tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr8
-rw-r--r--tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs52
-rw-r--r--tests/ui/const-generics/type_mismatch.stderr4
-rw-r--r--tests/ui/consts/const-eval/panic-assoc-never-type.rs2
-rw-r--r--tests/ui/consts/const-eval/transmute-size-mismatch.rs24
-rw-r--r--tests/ui/consts/const-eval/transmute-size-mismatch.stderr37
-rw-r--r--tests/ui/consts/const-eval/ub-enum.32bit.stderr4
-rw-r--r--tests/ui/consts/const-eval/ub-enum.64bit.stderr4
-rw-r--r--tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-link_cfg.stderr1
-rw-r--r--tests/ui/impl-trait/nested-return-type2.rs1
-rw-r--r--tests/ui/impl-trait/nested-return-type2.stderr17
-rw-r--r--tests/ui/impl-trait/nested-return-type3.rs1
-rw-r--r--tests/ui/impl-trait/nested-return-type3.stderr17
-rw-r--r--tests/ui/imports/auxiliary/glob-conflict.rs2
-rw-r--r--tests/ui/imports/issue-99695-b.fixed2
-rw-r--r--tests/ui/imports/issue-99695-b.rs2
-rw-r--r--tests/ui/imports/issue-99695.fixed2
-rw-r--r--tests/ui/imports/issue-99695.rs2
-rw-r--r--tests/ui/imports/local-modularized-tricky-fail-1.rs1
-rw-r--r--tests/ui/imports/local-modularized-tricky-fail-1.stderr14
-rw-r--r--tests/ui/lint/anonymous-reexport.rs16
-rw-r--r--tests/ui/lint/anonymous-reexport.stderr49
-rw-r--r--tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs33
-rw-r--r--tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr47
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr2
-rw-r--r--tests/ui/statics/uninhabited-static.stderr4
-rw-r--r--tests/ui/suggestions/issue-109436.rs13
-rw-r--r--tests/ui/suggestions/issue-109436.stderr15
-rw-r--r--tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs40
-rw-r--r--tests/ui/traits/new-solver/alias-sub.rs34
-rw-r--r--tests/ui/transmutability/issue-101739-1.stderr2
233 files changed, 3327 insertions, 1221 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3495f4d51af..449f0c73588 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4523,6 +4523,7 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
+ "serde_json",
  "smallvec",
  "stable_deref_trait",
  "stacker",
@@ -4826,6 +4827,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
+ "rustc_fs_util",
  "rustc_hir",
  "rustc_hir_analysis",
  "rustc_hir_typeck",
@@ -4950,6 +4952,7 @@ dependencies = [
  "rustc_errors",
  "rustc_expand",
  "rustc_feature",
+ "rustc_fs_util",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
@@ -5335,6 +5338,7 @@ dependencies = [
  "rustc_abi",
  "rustc_data_structures",
  "rustc_feature",
+ "rustc_fs_util",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index f67dae9beb9..c2a426bea09 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2222,6 +2222,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             }
                         }
                     }
+                    CastKind::Transmute => {
+                        span_mirbug!(
+                            self,
+                            rvalue,
+                            "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
+                        );
+                    }
                 }
             }
 
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index db05c00d211..2b6fcc169be 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle};
 use rustc_session::parse::ParseSess;
 use rustc_span::FileName;
 
-pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
+pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) {
     for raw_attr in attrs {
         let mut parser = rustc_parse::new_parser_from_source_str(
             parse_sess,
@@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
             start_span.to(end_span),
         ));
     }
-
-    krate
 }
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index a73fed6ccb2..378d5f39f4a 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -43,14 +43,14 @@ struct CollectProcMacros<'a> {
 }
 
 pub fn inject(
+    krate: &mut ast::Crate,
     sess: &Session,
     resolver: &mut dyn ResolverExpand,
-    mut krate: ast::Crate,
     is_proc_macro_crate: bool,
     has_proc_macro_decls: bool,
     is_test_crate: bool,
     handler: &rustc_errors::Handler,
-) -> ast::Crate {
+) {
     let ecfg = ExpansionConfig::default("proc_macro".to_string());
     let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
 
@@ -64,22 +64,20 @@ pub fn inject(
     };
 
     if has_proc_macro_decls || is_proc_macro_crate {
-        visit::walk_crate(&mut collect, &krate);
+        visit::walk_crate(&mut collect, krate);
     }
     let macros = collect.macros;
 
     if !is_proc_macro_crate {
-        return krate;
+        return;
     }
 
     if is_test_crate {
-        return krate;
+        return;
     }
 
     let decls = mk_decls(&mut cx, &macros);
     krate.items.push(decls);
-
-    krate
 }
 
 impl<'a> CollectProcMacros<'a> {
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index caed40d9fa8..6493c6f13d5 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -9,17 +9,19 @@ use rustc_span::DUMMY_SP;
 use thin_vec::thin_vec;
 
 pub fn inject(
-    mut krate: ast::Crate,
+    krate: &mut ast::Crate,
+    pre_configured_attrs: &[ast::Attribute],
     resolver: &mut dyn ResolverExpand,
     sess: &Session,
-) -> ast::Crate {
+) -> usize {
+    let orig_num_items = krate.items.len();
     let edition = sess.parse_sess.edition;
 
     // the first name in this list is the crate name of the crate with the prelude
-    let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
-        return krate;
-    } else if attr::contains_name(&krate.attrs, sym::no_std) {
-        if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
+    let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
+        return 0;
+    } else if attr::contains_name(pre_configured_attrs, sym::no_std) {
+        if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
             &[sym::core]
         } else {
             &[sym::core, sym::compiler_builtins]
@@ -88,6 +90,5 @@ pub fn inject(
     );
 
     krate.items.insert(0, use_item);
-
-    krate
+    krate.items.len() - orig_num_items
 }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 2d491b2dac8..43ab6c04428 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -37,7 +37,7 @@ struct TestCtxt<'a> {
 
 /// Traverse the crate, collecting all the test functions, eliding any
 /// existing main functions, and synthesizing a main test harness
-pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
+pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) {
     let span_diagnostic = sess.diagnostic();
     let panic_strategy = sess.panic_strategy();
     let platform_panic_strategy = sess.target.panic_strategy;
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 1b8e9312e2f..2107ae147e9 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -709,6 +709,10 @@ fn codegen_stmt<'tcx>(
                     let operand = codegen_operand(fx, operand);
                     operand.coerce_dyn_star(fx, lval);
                 }
+                Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
+                    let operand = codegen_operand(fx, operand);
+                    lval.write_cvalue_transmute(fx, operand);
+                }
                 Rvalue::Discriminant(place) => {
                     let place = codegen_place(fx, place);
                     let value = place.to_cvalue(fx);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index fe48cac4faf..03f2a65fcca 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -557,16 +557,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
             fx.bcx.ins().band(ptr, mask);
         }
 
-        sym::transmute => {
-            intrinsic_args!(fx, args => (from); intrinsic);
-
-            if ret.layout().abi.is_uninhabited() {
-                crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
-                return;
-            }
-
-            ret.write_cvalue_transmute(fx, from);
-        }
         sym::write_bytes | sym::volatile_set_memory => {
             intrinsic_args!(fx, args => (dst, val, count); intrinsic);
             let val = val.load_scalar(fx);
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index dd3268d7780..a570f2af0f0 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -189,6 +189,15 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 path.push(lib_name);
                 path
             };
+            // dlltool target architecture args from:
+            // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
+            let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
+                "x86_64" => ("i386:x86-64", "--64"),
+                "x86" => ("i386", "--32"),
+                "aarch64" => ("arm64", "--64"),
+                "arm" => ("arm", "--32"),
+                _ => panic!("unsupported arch {}", sess.target.arch),
+            };
             let result = std::process::Command::new(dlltool)
                 .args([
                     "-d",
@@ -197,6 +206,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                     lib_name,
                     "-l",
                     output_path.to_str().unwrap(),
+                    "-m",
+                    dlltool_target_arch,
+                    "-f",
+                    dlltool_target_bitness,
                     "--no-leading-underscore",
                     "--temp-prefix",
                     temp_prefix.to_str().unwrap(),
@@ -422,24 +435,22 @@ fn find_binutils_dlltool(sess: &Session) -> OsString {
         return dlltool_path.clone().into_os_string();
     }
 
-    let mut tool_name: OsString = if sess.host.arch != sess.target.arch {
-        // We are cross-compiling, so we need the tool with the prefix matching our target
-        if sess.target.arch == "x86" {
-            "i686-w64-mingw32-dlltool"
-        } else {
-            "x86_64-w64-mingw32-dlltool"
-        }
+    let tool_name: OsString = if sess.host.options.is_like_windows {
+        // If we're compiling on Windows, always use "dlltool.exe".
+        "dlltool.exe"
     } else {
-        // We are not cross-compiling, so we just want `dlltool`
-        "dlltool"
+        // On other platforms, use the architecture-specific name.
+        match sess.target.arch.as_ref() {
+            "x86_64" => "x86_64-w64-mingw32-dlltool",
+            "x86" => "i686-w64-mingw32-dlltool",
+            "aarch64" => "aarch64-w64-mingw32-dlltool",
+
+            // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
+            _ => "dlltool",
+        }
     }
     .into();
 
-    if sess.host.options.is_like_windows {
-        // If we're compiling on Windows, add the .exe suffix
-        tool_name.push(".exe");
-    }
-
     // NOTE: it's not clear how useful it is to explicitly search PATH.
     for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
         let full_path = dir.join(&tool_name);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 9c921989ca9..012e25884ca 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -378,7 +378,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 }
             }
 
-            _ => bug!("unknown intrinsic '{}'", name),
+            _ => bug!("unknown intrinsic '{}' -- should it have been lowered earlier?", name),
         };
 
         if !fn_abi.ret.is_ignore() {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 8dafe1b750b..e5bae009ed6 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend {
             .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
             .join(sess);
 
-        sess.time("llvm_dump_timing_file", || {
-            if sess.opts.unstable_opts.llvm_time_trace {
+        if sess.opts.unstable_opts.llvm_time_trace {
+            sess.time("llvm_dump_timing_file", || {
                 let file_name = outputs.with_extension("llvm_timings.json");
                 llvm_util::time_trace_profiler_finish(&file_name);
-            }
-        });
+            });
+        }
 
         Ok((codegen_results, work_products))
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 23e2b272410..dd117681950 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -133,6 +133,9 @@ pub fn get_linker<'a>(
         LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
             Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
         }
+        LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => {
+            Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
+        }
         LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
         LinkerFlavor::Gnu(cc, _)
         | LinkerFlavor::Darwin(cc, _)
@@ -1474,6 +1477,177 @@ impl<'a> L4Bender<'a> {
     }
 }
 
+/// Linker for AIX.
+pub struct AixLinker<'a> {
+    cmd: Command,
+    sess: &'a Session,
+    hinted_static: bool,
+}
+
+impl<'a> AixLinker<'a> {
+    pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
+        AixLinker { cmd: cmd, sess: sess, hinted_static: false }
+    }
+
+    fn hint_static(&mut self) {
+        if !self.hinted_static {
+            self.cmd.arg("-bstatic");
+            self.hinted_static = true;
+        }
+    }
+
+    fn hint_dynamic(&mut self) {
+        if self.hinted_static {
+            self.cmd.arg("-bdynamic");
+            self.hinted_static = false;
+        }
+    }
+
+    fn build_dylib(&mut self, _out_filename: &Path) {
+        self.cmd.arg("-bM:SRE");
+        self.cmd.arg("-bnoentry");
+        // FIXME: Use CreateExportList utility to create export list
+        // and remove -bexpfull.
+        self.cmd.arg("-bexpfull");
+    }
+}
+
+impl<'a> Linker for AixLinker<'a> {
+    fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
+        self.hint_dynamic();
+        self.cmd.arg(format!("-l{}", lib));
+    }
+
+    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
+        self.hint_static();
+        self.cmd.arg(format!("-l{}", lib));
+    }
+
+    fn link_rlib(&mut self, lib: &Path) {
+        self.hint_static();
+        self.cmd.arg(lib);
+    }
+
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
+    }
+
+    fn framework_path(&mut self, _: &Path) {
+        bug!("frameworks are not supported on AIX");
+    }
+
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
+    }
+
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn full_relro(&mut self) {}
+
+    fn partial_relro(&mut self) {}
+
+    fn no_relro(&mut self) {}
+
+    fn cmd(&mut self) -> &mut Command {
+        &mut self.cmd
+    }
+
+    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+        match output_kind {
+            LinkOutputKind::DynamicDylib => {
+                self.hint_dynamic();
+                self.build_dylib(out_filename);
+            }
+            LinkOutputKind::StaticDylib => {
+                self.hint_static();
+                self.build_dylib(out_filename);
+            }
+            _ => {}
+        }
+    }
+
+    fn link_rust_dylib(&mut self, lib: &str, _: &Path) {
+        self.hint_dynamic();
+        self.cmd.arg(format!("-l{}", lib));
+    }
+
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
+        bug!("frameworks not supported on AIX");
+    }
+
+    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
+        self.hint_static();
+        let lib = find_native_static_library(lib, verbatim, search_path, &self.sess);
+        self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
+    }
+
+    fn link_whole_rlib(&mut self, lib: &Path) {
+        self.hint_static();
+        self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
+    }
+
+    fn gc_sections(&mut self, _keep_metadata: bool) {
+        self.cmd.arg("-bgc");
+    }
+
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("-bnogc");
+    }
+
+    fn optimize(&mut self) {}
+
+    fn pgo_gen(&mut self) {}
+
+    fn control_flow_guard(&mut self) {}
+
+    fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
+        match strip {
+            Strip::None => {}
+            // FIXME: -s strips the symbol table, line number information
+            // and relocation information.
+            Strip::Debuginfo | Strip::Symbols => {
+                self.cmd.arg("-s");
+            }
+        }
+    }
+
+    fn no_crt_objects(&mut self) {}
+
+    fn no_default_libraries(&mut self) {}
+
+    fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+        let path = tmpdir.join("list.exp");
+        let res: io::Result<()> = try {
+            let mut f = BufWriter::new(File::create(&path)?);
+            // TODO: use llvm-nm to generate export list.
+            for symbol in symbols {
+                debug!("  _{}", symbol);
+                writeln!(f, "  {}", symbol)?;
+            }
+        };
+        if let Err(e) = res {
+            self.sess.fatal(&format!("failed to write export file: {}", e));
+        }
+        self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
+    }
+
+    fn subsystem(&mut self, _subsystem: &str) {}
+
+    fn reset_per_library_state(&mut self) {
+        self.hint_dynamic();
+    }
+
+    fn linker_plugin_lto(&mut self) {}
+
+    fn add_eh_frame_header(&mut self) {}
+
+    fn add_no_exec(&mut self) {}
+
+    fn add_as_needed(&mut self) {}
+}
+
 fn for_each_exported_symbols_include_dep<'tcx>(
     tcx: TyCtxt<'tcx>,
     crate_type: CrateType,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 4d34b3da5f5..c3c8649dbff 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
             total_codegen_time,
             start_rss.unwrap(),
             end_rss,
+            tcx.sess.opts.unstable_opts.time_passes_format,
         );
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index de1e00bd7a3..5da0e826c56 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -16,7 +16,7 @@ use rustc_index::vec::Idx;
 use rustc_middle::mir::{self, AssertKind, SwitchTargets};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
-use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, Instance, Ty};
 use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
@@ -769,23 +769,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             None => bx.fn_abi_of_fn_ptr(sig, extra_args),
         };
 
-        if intrinsic == Some(sym::transmute) {
-            return if let Some(target) = target {
-                self.codegen_transmute(bx, &args[0], destination);
-                helper.funclet_br(self, bx, target, mergeable_succ)
-            } else {
-                // If we are trying to transmute to an uninhabited type,
-                // it is likely there is no allotted destination. In fact,
-                // transmuting to an uninhabited type is UB, which means
-                // we can do what we like. Here, we declare that transmuting
-                // into an uninhabited type is impossible, so anything following
-                // it must be unreachable.
-                assert_eq!(fn_abi.ret.layout.abi, abi::Abi::Uninhabited);
-                bx.unreachable();
-                MergingSucc::False
-            };
-        }
-
         if let Some(merging_succ) = self.codegen_panic_intrinsic(
             &helper,
             bx,
@@ -828,7 +811,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         match intrinsic {
             None | Some(sym::drop_in_place) => {}
-            Some(sym::copy_nonoverlapping) => unreachable!(),
             Some(intrinsic) => {
                 let dest = match ret_dest {
                     _ if fn_abi.ret.is_indirect() => llargs[0],
@@ -1739,71 +1721,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
     }
 
-    fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir::Place<'tcx>) {
-        if let Some(index) = dst.as_local() {
-            match self.locals[index] {
-                LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
-                LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
-                LocalRef::Operand(None) => {
-                    let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref()));
-                    assert!(!dst_layout.ty.has_erasable_regions());
-                    let place = PlaceRef::alloca(bx, dst_layout);
-                    place.storage_live(bx);
-                    self.codegen_transmute_into(bx, src, place);
-                    let op = bx.load_operand(place);
-                    place.storage_dead(bx);
-                    self.locals[index] = LocalRef::Operand(Some(op));
-                    self.debug_introduce_local(bx, index);
-                }
-                LocalRef::Operand(Some(op)) => {
-                    assert!(op.layout.is_zst(), "assigning to initialized SSAtemp");
-                }
-            }
-        } else {
-            let dst = self.codegen_place(bx, dst.as_ref());
-            self.codegen_transmute_into(bx, src, dst);
-        }
-    }
-
-    fn codegen_transmute_into(
-        &mut self,
-        bx: &mut Bx,
-        src: &mir::Operand<'tcx>,
-        dst: PlaceRef<'tcx, Bx::Value>,
-    ) {
-        let src = self.codegen_operand(bx, src);
-
-        // Special-case transmutes between scalars as simple bitcasts.
-        match (src.layout.abi, dst.layout.abi) {
-            (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
-                // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
-                let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
-                let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
-                if src_is_ptr == dst_is_ptr {
-                    assert_eq!(src.layout.size, dst.layout.size);
-
-                    // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
-                    // conversions allow handling `bool`s the same as `u8`s.
-                    let src = bx.from_immediate(src.immediate());
-                    // LLVM also doesn't like `bitcast`s between pointers in different address spaces.
-                    let src_as_dst = if src_is_ptr {
-                        bx.pointercast(src, bx.backend_type(dst.layout))
-                    } else {
-                        bx.bitcast(src, bx.backend_type(dst.layout))
-                    };
-                    Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
-                    return;
-                }
-            }
-            _ => {}
-        }
-
-        let llty = bx.backend_type(src.layout);
-        let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
-        let align = src.layout.align.abi.min(dst.align);
-        src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, align));
-    }
-
     // Stores the return value of a function call into it's final location.
     fn store_return(
         &mut self,
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 13c4fa132d8..72d41d8c32c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
-use rustc_target::abi::VariantIdx;
+use rustc_target::abi::{self, VariantIdx};
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "trace", skip(self, bx))]
@@ -72,6 +72,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
+            mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
+                let src = self.codegen_operand(bx, operand);
+                self.codegen_transmute(bx, src, dest);
+            }
+
             mir::Rvalue::Repeat(ref elem, count) => {
                 let cg_elem = self.codegen_operand(bx, elem);
 
@@ -143,6 +148,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
     }
 
+    fn codegen_transmute(
+        &mut self,
+        bx: &mut Bx,
+        src: OperandRef<'tcx, Bx::Value>,
+        dst: PlaceRef<'tcx, Bx::Value>,
+    ) {
+        // The MIR validator enforces no unsized transmutes.
+        debug_assert!(src.layout.is_sized());
+        debug_assert!(dst.layout.is_sized());
+
+        if src.layout.size != dst.layout.size
+            || src.layout.abi == abi::Abi::Uninhabited
+            || dst.layout.abi == abi::Abi::Uninhabited
+        {
+            // In all of these cases it's UB to run this transmute, but that's
+            // known statically so might as well trap for it, rather than just
+            // making it unreachable.
+            bx.abort();
+            return;
+        }
+
+        let size_in_bytes = src.layout.size.bytes();
+        if size_in_bytes == 0 {
+            // Nothing to write
+            return;
+        }
+
+        match src.val {
+            OperandValue::Ref(src_llval, meta, src_align) => {
+                debug_assert_eq!(meta, None);
+                // For a place-to-place transmute, call `memcpy` directly so that
+                // both arguments get the best-available alignment information.
+                let bytes = bx.cx().const_usize(size_in_bytes);
+                let flags = MemFlags::empty();
+                bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags);
+            }
+            OperandValue::Immediate(_) | OperandValue::Pair(_, _) => {
+                // When we have immediate(s), the alignment of the source is irrelevant,
+                // so we can store them using the destination's alignment.
+                let llty = bx.backend_type(src.layout);
+                let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
+                src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, dst.align));
+            }
+        }
+    }
+
     pub fn codegen_rvalue_unsized(
         &mut self,
         bx: &mut Bx,
@@ -344,6 +395,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         };
                         OperandValue::Immediate(newval)
                     }
+                    mir::CastKind::Transmute => {
+                        bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand);
+                    }
                 };
                 OperandRef { val, layout: cast }
             }
@@ -673,6 +727,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
         match *rvalue {
+            mir::Rvalue::Cast(mir::CastKind::Transmute, ..) =>
+                // FIXME: Now that transmute is an Rvalue, it would be nice if
+                // it could create `Immediate`s for scalars, where possible.
+                false,
             mir::Rvalue::Ref(..) |
             mir::Rvalue::CopyForDeref(..) |
             mir::Rvalue::AddressOf(..) |
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index c14152a916a..163e3f86993 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -133,6 +133,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     bug!()
                 }
             }
+
+            Transmute => {
+                assert!(src.layout.is_sized());
+                assert!(dest.layout.is_sized());
+                if src.layout.size != dest.layout.size {
+                    throw_ub_format!(
+                        "transmuting from {}-byte type to {}-byte type: `{}` -> `{}`",
+                        src.layout.size.bytes(),
+                        dest.layout.size.bytes(),
+                        src.layout.ty,
+                        dest.layout.ty,
+                    );
+                }
+
+                self.copy_op(src, dest, /*allow_transmute*/ true)?;
+            }
         }
         Ok(())
     }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index a29cdade023..26fb041b455 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -127,7 +127,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // First handle intrinsics without return place.
         let ret = match ret {
             None => match intrinsic_name {
-                sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
                 sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
                 // Unsupported diverging intrinsic.
                 _ => return Ok(false),
@@ -411,9 +410,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.exact_div(&val, &size, dest)?;
             }
 
-            sym::transmute => {
-                self.copy_op(&args[0], dest, /*allow_transmute*/ true)?;
-            }
             sym::assert_inhabited
             | sym::assert_zero_valid
             | sym::assert_mem_uninitialized_valid => {
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index e0939d1d1ba..66fc1c07e20 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -621,6 +621,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             );
                         }
                     }
+                    CastKind::Transmute => {
+                        if let MirPhase::Runtime(..) = self.mir_phase {
+                            // Unlike `mem::transmute`, a MIR `Transmute` is well-formed
+                            // for any two `Sized` types, just potentially UB to run.
+
+                            if !op_ty.is_sized(self.tcx, self.param_env) {
+                                self.fail(
+                                    location,
+                                    format!("Cannot transmute from non-`Sized` type {op_ty:?}"),
+                                );
+                            }
+                            if !target_type.is_sized(self.tcx, self.param_env) {
+                                self.fail(
+                                    location,
+                                    format!("Cannot transmute to non-`Sized` type {target_type:?}"),
+                                );
+                            }
+                        } else {
+                            self.fail(
+                                location,
+                                format!(
+                                    "Transmute is not supported in non-runtime phase {:?}.",
+                                    self.mir_phase
+                                ),
+                            );
+                        }
+                    }
                 }
             }
             Rvalue::Repeat(_, _)
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 24cf9812a25..056ee1f63be 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -21,6 +21,7 @@ rustc-hash = "1.1.0"
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
+serde_json = "1.0.59"
 smallvec = { version = "1.8.1", features = [
     "const_generics",
     "union",
diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs
index 820a70fc8e4..513df666d0d 100644
--- a/compiler/rustc_data_structures/src/graph/scc/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs
@@ -56,7 +56,7 @@ fn test_three_sccs() {
     assert_eq!(sccs.scc(1), 0);
     assert_eq!(sccs.scc(2), 0);
     assert_eq!(sccs.scc(3), 2);
-    assert_eq!(sccs.successors(0), &[]);
+    assert_eq!(sccs.successors(0), &[] as &[usize]);
     assert_eq!(sccs.successors(1), &[0]);
     assert_eq!(sccs.successors(2), &[0]);
 }
@@ -113,7 +113,7 @@ fn test_find_state_2() {
     assert_eq!(sccs.scc(2), 0);
     assert_eq!(sccs.scc(3), 0);
     assert_eq!(sccs.scc(4), 0);
-    assert_eq!(sccs.successors(0), &[]);
+    assert_eq!(sccs.successors(0), &[] as &[usize]);
 }
 
 #[test]
@@ -138,7 +138,7 @@ fn test_find_state_3() {
     assert_eq!(sccs.scc(3), 0);
     assert_eq!(sccs.scc(4), 0);
     assert_eq!(sccs.scc(5), 1);
-    assert_eq!(sccs.successors(0), &[]);
+    assert_eq!(sccs.successors(0), &[] as &[usize]);
     assert_eq!(sccs.successors(1), &[0]);
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
index c8f97926717..7c866da6009 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs
@@ -27,11 +27,11 @@ fn successors() {
     let graph = create_graph();
     assert_eq!(graph.successors(0), &[1]);
     assert_eq!(graph.successors(1), &[2, 3]);
-    assert_eq!(graph.successors(2), &[]);
+    assert_eq!(graph.successors(2), &[] as &[usize]);
     assert_eq!(graph.successors(3), &[4]);
-    assert_eq!(graph.successors(4), &[]);
+    assert_eq!(graph.successors(4), &[] as &[usize]);
     assert_eq!(graph.successors(5), &[1]);
-    assert_eq!(graph.successors(6), &[]);
+    assert_eq!(graph.successors(6), &[] as &[usize]);
 }
 
 #[test]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 3d9c7f6eae2..58a0609e296 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
 pub use measureme::EventId;
 use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
 use parking_lot::RwLock;
+use serde_json::json;
 use smallvec::SmallVec;
 
 bitflags::bitflags! {
@@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
 /// Something that uniquely identifies a query invocation.
 pub struct QueryInvocationId(pub u32);
 
+/// Which format to use for `-Z time-passes`
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum TimePassesFormat {
+    /// Emit human readable text
+    Text,
+    /// Emit structured JSON
+    Json,
+}
+
 /// A reference to the SelfProfiler. It can be cloned and sent across thread
 /// boundaries at will.
 #[derive(Clone)]
@@ -158,14 +168,14 @@ pub struct SelfProfilerRef {
     // actually enabled.
     event_filter_mask: EventFilter,
 
-    // Print verbose generic activities to stderr?
-    print_verbose_generic_activities: bool,
+    // Print verbose generic activities to stderr.
+    print_verbose_generic_activities: Option<TimePassesFormat>,
 }
 
 impl SelfProfilerRef {
     pub fn new(
         profiler: Option<Arc<SelfProfiler>>,
-        print_verbose_generic_activities: bool,
+        print_verbose_generic_activities: Option<TimePassesFormat>,
     ) -> SelfProfilerRef {
         // If there is no SelfProfiler then the filter mask is set to NONE,
         // ensuring that nothing ever tries to actually access it.
@@ -207,9 +217,10 @@ impl SelfProfilerRef {
     /// a measureme event, "verbose" generic activities also print a timing entry to
     /// stderr if the compiler is invoked with -Ztime-passes.
     pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> {
-        let message = self.print_verbose_generic_activities.then(|| event_label.to_owned());
+        let message_and_format =
+            self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format));
 
-        VerboseTimingGuard::start(message, self.generic_activity(event_label))
+        VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label))
     }
 
     /// Like `verbose_generic_activity`, but with an extra arg.
@@ -221,11 +232,14 @@ impl SelfProfilerRef {
     where
         A: Borrow<str> + Into<String>,
     {
-        let message = self
+        let message_and_format = self
             .print_verbose_generic_activities
-            .then(|| format!("{}({})", event_label, event_arg.borrow()));
+            .map(|format| (format!("{}({})", event_label, event_arg.borrow()), format));
 
-        VerboseTimingGuard::start(message, self.generic_activity_with_arg(event_label, event_arg))
+        VerboseTimingGuard::start(
+            message_and_format,
+            self.generic_activity_with_arg(event_label, event_arg),
+        )
     }
 
     /// Start profiling a generic activity. Profiling continues until the
@@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> {
     }
 }
 
+struct VerboseInfo {
+    start_time: Instant,
+    start_rss: Option<usize>,
+    message: String,
+    format: TimePassesFormat,
+}
+
 #[must_use]
 pub struct VerboseTimingGuard<'a> {
-    start_and_message: Option<(Instant, Option<usize>, String)>,
+    info: Option<VerboseInfo>,
     _guard: TimingGuard<'a>,
 }
 
 impl<'a> VerboseTimingGuard<'a> {
-    pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self {
+    pub fn start(
+        message_and_format: Option<(String, TimePassesFormat)>,
+        _guard: TimingGuard<'a>,
+    ) -> Self {
         VerboseTimingGuard {
             _guard,
-            start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)),
+            info: message_and_format.map(|(message, format)| VerboseInfo {
+                start_time: Instant::now(),
+                start_rss: get_resident_set_size(),
+                message,
+                format,
+            }),
         }
     }
 
@@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> {
 
 impl Drop for VerboseTimingGuard<'_> {
     fn drop(&mut self) {
-        if let Some((start_time, start_rss, ref message)) = self.start_and_message {
+        if let Some(info) = &self.info {
             let end_rss = get_resident_set_size();
-            let dur = start_time.elapsed();
-            print_time_passes_entry(message, dur, start_rss, end_rss);
+            let dur = info.start_time.elapsed();
+            print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format);
         }
     }
 }
@@ -739,7 +768,22 @@ pub fn print_time_passes_entry(
     dur: Duration,
     start_rss: Option<usize>,
     end_rss: Option<usize>,
+    format: TimePassesFormat,
 ) {
+    match format {
+        TimePassesFormat::Json => {
+            let json = json!({
+                "pass": what,
+                "time": dur.as_secs_f64(),
+                "rss_start": start_rss,
+                "rss_end": end_rss,
+            });
+            eprintln!("time: {}", json.to_string());
+            return;
+        }
+        TimePassesFormat::Text => (),
+    }
+
     // Print the pass if its duration is greater than 5 ms, or it changed the
     // measured RSS.
     let is_notable = || {
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 8634c644176..1e835f6065a 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin;
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
-use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
+use rustc_data_structures::profiling::{
+    get_resident_set_size, print_time_passes_entry, TimePassesFormat,
+};
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{
@@ -161,7 +163,7 @@ pub trait Callbacks {
 
 #[derive(Default)]
 pub struct TimePassesCallbacks {
-    time_passes: bool,
+    time_passes: Option<TimePassesFormat>,
 }
 
 impl Callbacks for TimePassesCallbacks {
@@ -171,7 +173,8 @@ impl Callbacks for TimePassesCallbacks {
         // If a --print=... option has been given, we don't print the "total"
         // time because it will mess up the --print output. See #64339.
         //
-        self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
+        self.time_passes = (config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes)
+            .then(|| config.opts.unstable_opts.time_passes_format);
         config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
     }
 }
@@ -353,7 +356,7 @@ fn run_compiler(
 
             {
                 let plugins = queries.register_plugins()?;
-                let (_, lint_store) = &*plugins.borrow();
+                let (.., lint_store) = &*plugins.borrow();
 
                 // Lint plugins are registered; now we can process command line flags.
                 if sess.opts.describe_lints {
@@ -1354,9 +1357,9 @@ pub fn main() -> ! {
         RunCompiler::new(&args, &mut callbacks).run()
     });
 
-    if callbacks.time_passes {
+    if let Some(format) = callbacks.time_passes {
         let end_rss = get_resident_set_size();
-        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
+        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format);
     }
 
     process::exit(exit_code)
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 6eb0d24eb97..d32af10914e 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1002,6 +1002,7 @@ pub struct ExpansionData {
 pub struct ExtCtxt<'a> {
     pub sess: &'a Session,
     pub ecfg: expand::ExpansionConfig<'a>,
+    pub num_standard_library_imports: usize,
     pub reduced_recursion_limit: Option<Limit>,
     pub root_path: PathBuf,
     pub resolver: &'a mut dyn ResolverExpand,
@@ -1030,6 +1031,7 @@ impl<'a> ExtCtxt<'a> {
         ExtCtxt {
             sess,
             ecfg,
+            num_standard_library_imports: 0,
             reduced_recursion_limit: None,
             resolver,
             lint_store,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index d6cb173ba9b..a78dc0678d5 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -24,7 +24,6 @@ use rustc_session::Session;
 use rustc_span::edition::{Edition, ALL_EDITIONS};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use thin_vec::ThinVec;
 
 /// A folder that strips out items that do not belong in the current configuration.
 pub struct StripUnconfigured<'a> {
@@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> {
     pub lint_node_id: NodeId,
 }
 
-fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
+pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
     fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
         sess.emit_err(FeatureRemoved {
             span,
@@ -191,39 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
     features
 }
 
-/// `cfg_attr`-process the crate's attributes and compute the crate's features.
-pub fn features(
-    sess: &Session,
-    mut krate: ast::Crate,
-    lint_node_id: NodeId,
-) -> (ast::Crate, Features) {
-    let mut strip_unconfigured =
-        StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id };
-
-    let unconfigured_attrs = krate.attrs.clone();
-    let diag = &sess.parse_sess.span_diagnostic;
-    let err_count = diag.err_count();
-    let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) {
-        None => {
-            // The entire crate is unconfigured.
-            krate.attrs = ast::AttrVec::new();
-            krate.items = ThinVec::new();
-            Features::default()
-        }
-        Some(attrs) => {
-            krate.attrs = attrs;
-            let features = get_features(sess, &krate.attrs);
-            if err_count == diag.err_count() {
-                // Avoid reconfiguring malformed `cfg_attr`s.
-                strip_unconfigured.features = Some(&features);
-                // Run configuration again, this time with features available
-                // so that we can perform feature-gating.
-                strip_unconfigured.configure_krate_attrs(unconfigured_attrs);
-            }
-            features
-        }
+pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec {
+    let strip_unconfigured = StripUnconfigured {
+        sess,
+        features: None,
+        config_tokens: false,
+        lint_node_id: ast::CRATE_NODE_ID,
     };
-    (krate, features)
+    let attrs: ast::AttrVec =
+        attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect();
+    if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() }
 }
 
 #[macro_export]
@@ -254,11 +230,6 @@ impl<'a> StripUnconfigured<'a> {
         }
     }
 
-    fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option<ast::AttrVec> {
-        attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
-        self.in_cfg(&attrs).then_some(attrs)
-    }
-
     /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`.
     /// This is only used during the invocation of `derive` proc-macros,
     /// which require that we cfg-expand their entire input.
@@ -281,7 +252,7 @@ impl<'a> StripUnconfigured<'a> {
             .iter()
             .flat_map(|tree| match tree.clone() {
                 AttrTokenTree::Attributes(mut data) => {
-                    data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
+                    data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
 
                     if self.in_cfg(&data.attrs) {
                         data.tokens = LazyAttrTokenStream::new(
@@ -319,12 +290,16 @@ impl<'a> StripUnconfigured<'a> {
     /// the syntax of any `cfg_attr` is incorrect.
     fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) {
         node.visit_attrs(|attrs| {
-            attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
+            attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
         });
     }
 
-    fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
-        if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] }
+    fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> {
+        if attr.has_name(sym::cfg_attr) {
+            self.expand_cfg_attr(attr, true)
+        } else {
+            vec![attr.clone()]
+        }
     }
 
     /// Parse and expand a single `cfg_attr` attribute into a list of attributes
@@ -334,9 +309,9 @@ impl<'a> StripUnconfigured<'a> {
     /// Gives a compiler warning when the `cfg_attr` contains no attributes and
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
-    pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
+    pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
         let Some((cfg_predicate, expanded_attrs)) =
-            rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else {
+            rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else {
                 return vec![];
             };
 
@@ -365,10 +340,10 @@ impl<'a> StripUnconfigured<'a> {
             //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
             expanded_attrs
                 .into_iter()
-                .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item)))
+                .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item)))
                 .collect()
         } else {
-            expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect()
+            expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect()
         }
     }
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 4092a192e0c..ec40911545f 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     ) -> Result<Self::OutputTy, Self> {
         Ok(noop_flat_map(node, collector))
     }
+    fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
+        collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
+    }
 }
 
 impl InvocationCollectorNode for P<ast::Item> {
@@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate {
     fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
         noop_visit_crate(self, visitor)
     }
+    fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) {
+        self.attrs.clear();
+        // Standard prelude imports are left in the crate for backward compatibility.
+        self.items.truncate(collector.cx.num_standard_library_imports);
+    }
 }
 
 impl InvocationCollectorNode for P<ast::Ty> {
@@ -1688,7 +1696,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         res
     }
 
-    fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) {
+    fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
         node.visit_attrs(|attrs| {
             // Repeated `insert` calls is inefficient, but the number of
             // insertions is almost always 0 or 1 in practice.
@@ -1712,7 +1720,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         Default::default()
                     }
                     sym::cfg_attr => {
-                        self.expand_cfg_attr(&mut node, attr, pos);
+                        self.expand_cfg_attr(&mut node, &attr, pos);
                         continue;
                     }
                     _ => {
@@ -1756,11 +1764,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                             continue;
                         }
 
-                        self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() });
+                        node.expand_cfg_false(self, span);
                         continue;
                     }
                     sym::cfg_attr => {
-                        self.expand_cfg_attr(node, attr, pos);
+                        self.expand_cfg_attr(node, &attr, pos);
                         continue;
                     }
                     _ => visit_clobber(node, |node| {
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index e0a7c864b94..b7d280b8751 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -160,6 +160,8 @@ declare_features! (
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
+    /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
+    (active, link_cfg, "1.14.0", None, None),
     /// Allows the `multiple_supertrait_upcastable` lint.
     (active, multiple_supertrait_upcastable, "1.69.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
@@ -432,8 +434,6 @@ declare_features! (
     (active, large_assignments, "1.52.0", Some(83518), None),
     /// Allows `if/while p && let q = r && ...` chains.
     (active, let_chains, "1.37.0", Some(53667), None),
-    /// Allows `#[link(..., cfg(..))]`.
-    (active, link_cfg, "1.14.0", Some(37406), None),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
     (active, lint_reasons, "1.31.0", Some(54503), None),
     /// Give access to additional metadata about declarative macro meta-variables.
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index a7dfce3b9b8..81d63338145 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -1,10 +1,11 @@
+#![feature(absolute_path)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
 use std::ffi::CString;
 use std::fs;
 use std::io;
-use std::path::{Path, PathBuf};
+use std::path::{absolute, Path, PathBuf};
 
 // Unfortunately, on windows, it looks like msvcrt.dll is silently translating
 // verbatim paths under the hood to non-verbatim paths! This manifests itself as
@@ -91,3 +92,8 @@ pub fn path_to_c_string(p: &Path) -> CString {
 pub fn path_to_c_string(p: &Path) -> CString {
     CString::new(p.to_str().unwrap()).unwrap()
 }
+
+#[inline]
+pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    fs::canonicalize(&path).or_else(|_| absolute(&path))
+}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 894995c1bfc..6d9dfe9697c 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1336,7 +1336,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
                 },
                 ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ObjectSafe(_)
                 | ty::PredicateKind::ClosureKind(_, _, _)
                 | ty::PredicateKind::Subtype(_)
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index d4dfe455b29..3d37e0ce0c6 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -11,7 +11,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections};
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
@@ -97,12 +97,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 }
             }
 
-            if let Some(simp) = simplify_type(
-                self.tcx,
-                self_ty,
-                TreatParams::AsCandidateKey,
-                TreatProjections::AsCandidateKey,
-            ) {
+            if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) {
                 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
             } else {
                 bug!("unexpected self type: {:?}", self_ty);
@@ -162,12 +157,7 @@ impl<'tcx> InherentCollect<'tcx> {
             }
         }
 
-        if let Some(simp) = simplify_type(
-            self.tcx,
-            ty,
-            TreatParams::AsCandidateKey,
-            TreatProjections::AsCandidateKey,
-        ) {
+        if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) {
             self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
         } else {
             bug!("unexpected primitive type: {:?}", ty);
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 23490bc091c..465e787c92a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -133,8 +133,8 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
         check_impl(tcx, impl_def_id, trait_ref);
         check_object_overlap(tcx, impl_def_id, trait_ref);
 
-        tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id));
-        tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id));
+        unsafety::check_item(tcx, impl_def_id);
+        tcx.ensure().orphan_check_impl(impl_def_id);
     }
 
     builtin::check_trait(tcx, def_id);
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 91c64eeec1e..7f1e4ccc964 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -528,7 +528,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
         | ty::PredicateKind::Clause(ty::Clause::Projection(_))
         | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-        | ty::PredicateKind::AliasEq(..)
+        | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::WellFormed(_)
         | ty::PredicateKind::Subtype(_)
         | ty::PredicateKind::Coerce(_)
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 9ee6785970c..357deb07b8f 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -56,7 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateKind::Clause(ty::Clause::Projection(..))
                     | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
                     | ty::PredicateKind::WellFormed(..)
-                    | ty::PredicateKind::AliasEq(..)
+                    | ty::PredicateKind::AliasRelate(..)
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 8455076de56..3def97bca47 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -666,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
                 | ty::PredicateKind::WellFormed(..)
                 | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 // N.B., this predicate is created by breaking down a
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index ec14bd3c6f4..e0ddb90c33b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use rustc_span::{self, Span};
+use rustc_span::{self, symbol::kw, Span};
 use rustc_trait_selection::traits;
 
 use std::ops::ControlFlow;
@@ -25,17 +25,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let generics = self.tcx.generics_of(def_id);
         let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
-            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
-            _ => ty::List::empty(),
+            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(),
+            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+                pred.projection_ty.substs.to_vec()
+            }
+            ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => {
+                vec![ty.into(), arg.into()]
+            }
+            ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()],
+            _ => return false,
         };
 
-        let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
-            predicate_substs.types().find_map(|ty| {
-                ty.walk().find_map(|arg| {
+        let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| {
+            predicate_substs.iter().find_map(|arg| {
+                arg.walk().find_map(|arg| {
                     if let ty::GenericArgKind::Type(ty) = arg.unpack()
-                        && let ty::Param(param_ty) = ty.kind()
-                        && matches(param_ty)
+                        && let ty::Param(param_ty) = *ty.kind()
+                        && matches(ty::ParamTerm::Ty(param_ty))
+                    {
+                        Some(arg)
+                    } else if let ty::GenericArgKind::Const(ct) = arg.unpack()
+                        && let ty::ConstKind::Param(param_ct) = ct.kind()
+                        && matches(ty::ParamTerm::Const(param_ct))
                     {
                         Some(arg)
                     } else {
@@ -47,21 +58,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Prefer generics that are local to the fn item, since these are likely
         // to be the cause of the unsatisfied predicate.
-        let mut param_to_point_at = find_param_matching(&|param_ty| {
-            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
+        let mut param_to_point_at = find_param_matching(&|param_term| {
+            self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id
         });
         // Fall back to generic that isn't local to the fn item. This will come
         // from a trait or impl, for example.
-        let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
-            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
-                && param_ty.name != rustc_span::symbol::kw::SelfUpper
+        let mut fallback_param_to_point_at = find_param_matching(&|param_term| {
+            self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id
+                && !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper)
         });
         // Finally, the `Self` parameter is possibly the reason that the predicate
         // is unsatisfied. This is less likely to be true for methods, because
         // method probe means that we already kinda check that the predicates due
         // to the `Self` type are true.
-        let mut self_param_to_point_at =
-            find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
+        let mut self_param_to_point_at = find_param_matching(
+            &|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper),
+        );
 
         // Finally, for ambiguity-related errors, we actually want to look
         // for a parameter that is the source of the inference type left
@@ -225,14 +237,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
         let Some((index, _)) = own_substs
             .iter()
-            .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
             .enumerate()
             .find(|(_, arg)| **arg == param_to_point_at) else { return false };
         let Some(arg) = segment
             .args()
             .args
             .iter()
-            .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
             .nth(index) else { return false; };
         error.obligation.cause.span = arg
             .span()
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index b6d39341fe7..dab709e17f0 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -16,7 +16,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_middle::middle::stability;
-use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::AssocItem;
 use rustc_middle::ty::GenericParamDefKind;
@@ -701,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     }
 
     fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
-        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey) else {
+        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else {
             bug!("unexpected incoherent type: {:?}", self_ty)
         };
         for &impl_def_id in self.tcx.incoherent_impls(simp) {
@@ -838,7 +837,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             }
         });
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index b219be4ae19..55f684599e7 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -25,7 +25,6 @@ use rustc_infer::infer::{
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
 use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
@@ -1524,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .into_iter()
             .any(|info| self.associated_value(info.def_id, item_name).is_some());
         let found_assoc = |ty: Ty<'tcx>| {
-            simplify_type(tcx, ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey)
+            simplify_type(tcx, ty, TreatParams::AsCandidateKey)
                 .and_then(|simp| {
                     tcx.incoherent_impls(simp)
                         .iter()
@@ -2653,12 +2652,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // FIXME: Even though negative bounds are not implemented, we could maybe handle
                 // cases where a positive bound implies a negative impl.
                 (candidates, Vec::new())
-            } else if let Some(simp_rcvr_ty) = simplify_type(
-                self.tcx,
-                rcvr_ty,
-                TreatParams::ForLookup,
-                TreatProjections::ForLookup,
-            ) {
+            } else if let Some(simp_rcvr_ty) =
+                simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup)
+            {
                 let mut potential_candidates = Vec::new();
                 let mut explicitly_negative = Vec::new();
                 for candidate in candidates {
@@ -2671,12 +2667,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         })
                         .any(|imp_did| {
                             let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
-                            let imp_simp = simplify_type(
-                                self.tcx,
-                                imp.self_ty(),
-                                TreatParams::ForLookup,
-                                TreatProjections::ForLookup,
-                            );
+                            let imp_simp =
+                                simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
                         })
                     {
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 4deae9f41c7..d6f83838a04 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -108,7 +108,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::{base_n, flock};
 use rustc_errors::ErrorGuaranteed;
-use rustc_fs_util::{link_or_copy, LinkOrCopy};
+use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
 use rustc_session::{Session, StableCrateId};
 use rustc_span::Symbol;
 
@@ -223,7 +223,7 @@ pub fn prepare_session_directory(
     // because, on windows, long paths can cause problems;
     // canonicalization inserts this weird prefix that makes windows
     // tolerate long paths.
-    let crate_dir = match crate_dir.canonicalize() {
+    let crate_dir = match try_canonicalize(&crate_dir) {
         Ok(v) => v,
         Err(err) => {
             return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err }));
@@ -867,7 +867,7 @@ fn all_except_most_recent(
 /// before passing it to std::fs::remove_dir_all(). This will convert the path
 /// into the '\\?\' format, which supports much longer paths.
 fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
-    let canonicalized = match std_fs::canonicalize(p) {
+    let canonicalized = match try_canonicalize(p) {
         Ok(canonicalized) => canonicalized,
         Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
         Err(err) => return Err(err),
@@ -877,7 +877,7 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
 }
 
 fn safe_remove_file(p: &Path) -> io::Result<()> {
-    let canonicalized = match std_fs::canonicalize(p) {
+    let canonicalized = match try_canonicalize(p) {
         Ok(canonicalized) => canonicalized,
         Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
         Err(err) => return Err(err),
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 4503af03ca3..88a28e26005 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> {
             (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
                 if self.tcx.trait_solver_next() =>
             {
-                relation.register_type_equate_obligation(a, b);
+                relation.register_type_relate_obligation(a, b);
                 Ok(a)
             }
 
@@ -842,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
         let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
 
         self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
-            ty::PredicateKind::AliasEq(a.into(), b.into())
+            ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
         } else {
             ty::PredicateKind::ConstEquate(a, b)
         })]);
     }
 
-    /// Register an obligation that both types must be equal to each other.
-    ///
-    /// If they aren't equal then the relation doesn't hold.
-    fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
-        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
-
-        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
+    /// Register an obligation that both types must be related to each other according to
+    /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
+    fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
             a.into(),
             b.into(),
+            self.alias_relate_direction(),
         ))]);
     }
+
+    /// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
+    /// of the relation.
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
 }
 
 fn int_unification_error<'tcx>(
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index c92a74b6241..38002357cde 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -210,4 +210,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        ty::AliasRelationDirection::Equate
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 5c12351226a..6395c4d4b20 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        // FIXME(deferred_projection_equality): This isn't right, I think?
+        ty::AliasRelationDirection::Equate
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index dbef42db8f1..98cbd4c561c 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations)
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        // FIXME(deferred_projection_equality): This isn't right, I think?
+        ty::AliasRelationDirection::Equate
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 2320f6bfb16..f5d20cb7ebf 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -711,6 +711,34 @@ where
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.delegate.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
+    }
+
+    fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
+            ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
+                a.into(),
+                b.into(),
+                ty::AliasRelationDirection::Subtype,
+            ),
+            // a :> b is b <: a
+            ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
+                b.into(),
+                a.into(),
+                ty::AliasRelationDirection::Subtype,
+            ),
+            ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
+                a.into(),
+                b.into(),
+                ty::AliasRelationDirection::Equate,
+            ),
+            // FIXME(deferred_projection_equality): Implement this when we trigger it.
+            // Probably just need to do nothing here.
+            ty::Variance::Bivariant => unreachable!(),
+        })]);
+    }
 }
 
 /// When we encounter a binder like `for<..> fn(..)`, we actually have
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 83f3d5a74fb..048dad3a48b 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -22,7 +22,7 @@ pub fn explicit_outlives_bounds<'tcx>(
             ty::PredicateKind::Clause(ty::Clause::Projection(..))
             | ty::PredicateKind::Clause(ty::Clause::Trait(..))
             | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::WellFormed(..)
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index f795047709e..fa6529dfa93 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> {
             // completely change the normalization routine with the new solver.
             //
             // The new solver correctly handles projection equality so this hack
-            // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
+            // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
             // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
             // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
             return projection_ty.to_ty(self.tcx);
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 230cadb1184..fc73ca7606d 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -236,4 +236,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        ty::AliasRelationDirection::Subtype
+    }
 }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index c07ff516579..0d2faeba5fc 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -293,7 +293,7 @@ impl<'tcx> Elaborator<'tcx> {
                 // Nothing to elaborate
             }
             ty::PredicateKind::Ambiguous => {}
-            ty::PredicateKind::AliasEq(..) => {
+            ty::PredicateKind::AliasRelate(..) => {
                 // No
             }
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index ac6e8fca695..96d6a1cb062 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_borrowck = { path = "../rustc_borrowck" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
 rustc_expand = { path = "../rustc_expand" }
+rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 71bdd4df95b..413b40ab808 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result};
 use crate::proc_macro_decls;
 use crate::util;
 
-use ast::CRATE_NODE_ID;
 use rustc_ast::{self as ast, visit};
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -12,6 +11,7 @@ use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::PResult;
 use rustc_expand::base::{ExtCtxt, LintStoreExpand};
+use rustc_fs_util::try_canonicalize;
 use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
@@ -76,22 +76,14 @@ pub fn register_plugins<'a>(
     sess: &'a Session,
     metadata_loader: &'a dyn MetadataLoader,
     register_lints: impl Fn(&Session, &mut LintStore),
-    mut krate: ast::Crate,
+    pre_configured_attrs: &[ast::Attribute],
     crate_name: Symbol,
-) -> Result<(ast::Crate, LintStore)> {
-    krate = sess.time("attributes_injection", || {
-        rustc_builtin_macros::cmdline_attrs::inject(
-            krate,
-            &sess.parse_sess,
-            &sess.opts.unstable_opts.crate_attr,
-        )
-    });
-
-    let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID);
+) -> Result<LintStore> {
     // these need to be set "early" so that expansion sees `quote` if enabled.
+    let features = rustc_expand::config::features(sess, pre_configured_attrs);
     sess.init_features(features);
 
-    let crate_types = util::collect_crate_types(sess, &krate.attrs);
+    let crate_types = util::collect_crate_types(sess, pre_configured_attrs);
     sess.init_crate_types(crate_types);
 
     let stable_crate_id = StableCrateId::new(
@@ -117,8 +109,9 @@ pub fn register_plugins<'a>(
     let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
     register_lints(sess, &mut lint_store);
 
-    let registrars =
-        sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate));
+    let registrars = sess.time("plugin_loading", || {
+        plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs)
+    });
     sess.time("plugin_registration", || {
         let mut registry = plugin::Registry { lint_store: &mut lint_store };
         for registrar in registrars {
@@ -126,7 +119,7 @@ pub fn register_plugins<'a>(
         }
     });
 
-    Ok((krate, lint_store))
+    Ok(lint_store)
 }
 
 fn pre_expansion_lint<'a>(
@@ -173,19 +166,29 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
 /// harness if one is to be provided, injection of a dependency on the
 /// standard library and prelude, and name resolution.
 #[instrument(level = "trace", skip(krate, resolver))]
-fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate {
+fn configure_and_expand(
+    mut krate: ast::Crate,
+    pre_configured_attrs: &[ast::Attribute],
+    resolver: &mut Resolver<'_, '_>,
+) -> ast::Crate {
     let tcx = resolver.tcx();
     let sess = tcx.sess;
     let lint_store = unerased_lint_store(tcx);
     let crate_name = tcx.crate_name(LOCAL_CRATE);
-    pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name);
+    let lint_check_node = (&krate, pre_configured_attrs);
+    pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name);
     rustc_builtin_macros::register_builtin_macros(resolver);
 
-    krate = sess.time("crate_injection", || {
-        rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess)
+    let num_standard_library_imports = sess.time("crate_injection", || {
+        rustc_builtin_macros::standard_library_imports::inject(
+            &mut krate,
+            pre_configured_attrs,
+            resolver,
+            sess,
+        )
     });
 
-    util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
+    util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer());
 
     // Expand all macros
     krate = sess.time("macro_expand_crate", || {
@@ -222,7 +225,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
 
         // Create the config for macro expansion
         let features = sess.features_untracked();
-        let recursion_limit = get_recursion_limit(&krate.attrs, sess);
+        let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
         let cfg = rustc_expand::expand::ExpansionConfig {
             features: Some(features),
             recursion_limit,
@@ -235,6 +238,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
 
         let lint_store = LintStoreExpandImpl(lint_store);
         let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
+        ecx.num_standard_library_imports = num_standard_library_imports;
         // Expand macros now!
         let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
 
@@ -263,7 +267,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
     });
 
     sess.time("maybe_building_test_harness", || {
-        rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate)
+        rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver)
     });
 
     let has_proc_macro_decls = sess.time("AST_validation", || {
@@ -287,12 +291,12 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
         sess.emit_warning(errors::ProcMacroCratePanicAbort);
     }
 
-    krate = sess.time("maybe_create_a_macro_crate", || {
+    sess.time("maybe_create_a_macro_crate", || {
         let is_test_crate = sess.opts.test;
         rustc_builtin_macros::proc_macro_harness::inject(
+            &mut krate,
             sess,
             resolver,
-            krate,
             is_proc_macro_crate,
             has_proc_macro_decls,
             is_test_crate,
@@ -356,7 +360,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
         tcx.registered_tools(()),
         Some(lint_buffer),
         rustc_lint::BuiltinCombinedEarlyLintPass::new(),
-        &**krate,
+        (&**krate, &*krate.attrs),
     )
 }
 
@@ -405,12 +409,12 @@ where
 }
 
 fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
-    let input_path = input_path.canonicalize().ok();
+    let input_path = try_canonicalize(input_path).ok();
     if input_path.is_none() {
         return false;
     }
     let check = |output_path: &PathBuf| {
-        if output_path.canonicalize().ok() == input_path { Some(()) } else { None }
+        if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None }
     };
     check_output(output_paths, check).is_some()
 }
@@ -557,9 +561,9 @@ fn resolver_for_lowering<'tcx>(
 ) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
     let arenas = Resolver::arenas();
     let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`.
-    let krate = tcx.crate_for_resolver(()).steal();
-    let mut resolver = Resolver::new(tcx, &krate, &arenas);
-    let krate = configure_and_expand(krate, &mut resolver);
+    let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal();
+    let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas);
+    let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
 
     // Make sure we don't mutate the cstore from here on.
     tcx.untracked().cstore.leak();
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 58ad044b399..d2293780836 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -88,8 +88,9 @@ pub struct Queries<'tcx> {
 
     dep_graph_future: Query<Option<DepGraphFuture>>,
     parse: Query<ast::Crate>,
+    pre_configure: Query<(ast::Crate, ast::AttrVec)>,
     crate_name: Query<Symbol>,
-    register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
+    register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
     // This just points to what's in `gcx_cell`.
     gcx: Query<&'tcx GlobalCtxt<'tcx>>,
@@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> {
             hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
             dep_graph_future: Default::default(),
             parse: Default::default(),
+            pre_configure: Default::default(),
             crate_name: Default::default(),
             register_plugins: Default::default(),
             dep_graph: Default::default(),
@@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> {
             .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
     }
 
-    pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
+    pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
+        self.pre_configure.compute(|| {
+            let mut krate = self.parse()?.steal();
+
+            let sess = self.session();
+            rustc_builtin_macros::cmdline_attrs::inject(
+                &mut krate,
+                &sess.parse_sess,
+                &sess.opts.unstable_opts.crate_attr,
+            );
+
+            let pre_configured_attrs =
+                rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
+            Ok((krate, pre_configured_attrs))
+        })
+    }
+
+    pub fn register_plugins(
+        &self,
+    ) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> {
         self.register_plugins.compute(|| {
             let crate_name = *self.crate_name()?.borrow();
-            let krate = self.parse()?.steal();
+            let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
 
             let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
-            let (krate, lint_store) = passes::register_plugins(
+            let lint_store = passes::register_plugins(
                 self.session(),
                 &*self.codegen_backend().metadata_loader(),
                 self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
-                krate,
+                &pre_configured_attrs,
                 crate_name,
             )?;
 
@@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> {
             // called, which happens within passes::register_plugins().
             self.dep_graph_future().ok();
 
-            Ok((krate, Lrc::new(lint_store)))
+            Ok((krate, pre_configured_attrs, Lrc::new(lint_store)))
         })
     }
 
     fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
         self.crate_name.compute(|| {
             Ok({
-                let parse_result = self.parse()?;
-                let krate = parse_result.borrow();
+                let pre_configure_result = self.pre_configure()?;
+                let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
                 // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
-                find_crate_name(self.session(), &krate.attrs)
+                find_crate_name(self.session(), pre_configured_attrs)
             })
         })
     }
@@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> {
     pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
         self.gcx.compute(|| {
             let crate_name = *self.crate_name()?.borrow();
-            let (krate, lint_store) = self.register_plugins()?.steal();
+            let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal();
 
             let sess = self.session();
 
@@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> {
                 feed.crate_name(crate_name);
 
                 let feed = tcx.feed_unit_query();
-                feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate)));
+                feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
                 feed.metadata_loader(
                     tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())),
                 );
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 014810dba9c..eb5990507fb 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -2,6 +2,7 @@
 use crate::interface::parse_cfgspecs;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::rustc_optgroups;
 use rustc_session::config::Input;
@@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(threads, 99);
     untracked!(time_llvm_passes, true);
     untracked!(time_passes, true);
+    untracked!(time_passes_format, TimePassesFormat::Json);
     untracked!(trace_macros, true);
     untracked!(track_diagnostics, true);
     untracked!(trim_diagnostic_paths, false);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c822237413c..68e62c9789a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -508,6 +508,3 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
     .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
-
-lint_useless_anonymous_reexport = useless anonymous re-export
-    .note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}`
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 29ba480cdd2..64c3ef45137 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1600,7 +1600,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
                     Clause(Clause::Projection(..)) |
-                    AliasEq(..) |
+                    AliasRelate(..) |
                     // Ignore bounds that a user can't type
                     WellFormed(..) |
                     ObjectSafe(..) |
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index f5a711315ea..626c09fea07 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -910,6 +910,10 @@ pub trait LintContext: Sized {
                         Applicability::MachineApplicable,
                     );
                 }
+                BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => {
+                    db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace));
+                    db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace));
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(db)
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index fc151730223..65607d71805 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -340,7 +340,7 @@ pub trait EarlyCheckNode<'a>: Copy {
         'a: 'b;
 }
 
-impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
+impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
     fn id(self) -> ast::NodeId {
         ast::CRATE_NODE_ID
     }
@@ -348,15 +348,15 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
     where
         'a: 'b,
     {
-        &self.attrs
+        &self.1
     }
     fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
     where
         'a: 'b,
     {
-        lint_callback!(cx, check_crate, self);
-        ast_visit::walk_crate(cx, self);
-        lint_callback!(cx, check_crate_post, self);
+        lint_callback!(cx, check_crate, self.0);
+        ast_visit::walk_crate(cx, self.0);
+        lint_callback!(cx, check_crate_post, self.0);
     }
 }
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c2cc2fcdf55..b3578540516 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -74,7 +74,6 @@ mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
-mod reexports;
 mod traits;
 mod types;
 mod unused;
@@ -112,7 +111,6 @@ use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
 use redundant_semicolon::*;
-use reexports::*;
 use traits::*;
 use types::*;
 use unused::*;
@@ -244,7 +242,6 @@ late_lint_methods!(
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
             MapUnitFn: MapUnitFn,
-            UselessAnonymousReexport: UselessAnonymousReexport,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 46a025f41e0..308c02929ca 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1528,11 +1528,3 @@ pub struct UnusedAllocationDiag;
 #[derive(LintDiagnostic)]
 #[diag(lint_unused_allocation_mut)]
 pub struct UnusedAllocationMutDiag;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_useless_anonymous_reexport)]
-#[note]
-pub struct UselessAnonymousReexportDiag {
-    pub article: &'static str,
-    pub desc: &'static str,
-}
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 883a56cb3ce..f9d43fe2200 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -27,6 +27,8 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
+    /// #![feature(type_alias_impl_trait)]
+    ///
     /// trait Duh {}
     ///
     /// impl Duh for i32 {}
@@ -41,7 +43,9 @@ declare_lint! {
     ///     type Assoc = F;
     /// }
     ///
-    /// fn test() -> impl Trait<Assoc = impl Sized> {
+    /// type Tait = impl Sized;
+    ///
+    /// fn test() -> impl Trait<Assoc = Tait> {
     ///     42
     /// }
     /// ```
@@ -54,7 +58,7 @@ declare_lint! {
     ///
     /// Although the hidden type, `i32` does satisfy this bound, we do not
     /// consider the return type to be well-formed with this lint. It can be
-    /// fixed by changing `impl Sized` into `impl Sized + Send`.
+    /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`.
     pub OPAQUE_HIDDEN_INFERRED_BOUND,
     Warn,
     "detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
@@ -64,7 +68,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
+        let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; };
         let def_id = item.owner_id.def_id.to_def_id();
         let infcx = &cx.tcx.infer_ctxt().build();
         // For every projection predicate in the opaque type's explicit bounds,
@@ -81,6 +85,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             // have opaques in them anyways.
             let Some(proj_term) = proj.term.ty() else { continue };
 
+            // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
+            if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
+                && cx.tcx.parent(opaque_ty.def_id) == def_id
+                && matches!(
+                    opaque.origin,
+                    hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
+                )
+            {
+                continue;
+            }
+
             let proj_ty =
                 cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs);
             // For every instance of the projection type in the bounds,
diff --git a/compiler/rustc_lint/src/reexports.rs b/compiler/rustc_lint/src/reexports.rs
deleted file mode 100644
index 8737a57ea02..00000000000
--- a/compiler/rustc_lint/src/reexports.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use crate::lints::UselessAnonymousReexportDiag;
-use crate::{LateContext, LateLintPass, LintContext};
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
-use rustc_hir::{Item, ItemKind, UseKind};
-use rustc_middle::ty::Visibility;
-use rustc_span::symbol::kw;
-use rustc_span::Span;
-
-declare_lint! {
-    /// The `useless_anonymous_reexport` lint checks if anonymous re-exports
-    /// are re-exports of traits.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![deny(useless_anonymous_reexport)]
-    ///
-    /// mod sub {
-    ///     pub struct Bar;
-    /// }
-    ///
-    /// pub use self::sub::Bar as _;
-    /// # fn main() {}
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Anonymous re-exports are only useful if it's a re-export of a trait
-    /// in case you want to give access to it. If you re-export any other kind,
-    /// you won't be able to use it since its name won't be accessible.
-    pub USELESS_ANONYMOUS_REEXPORT,
-    Warn,
-    "useless anonymous re-export"
-}
-
-declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]);
-
-fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) {
-    let article = cx.tcx.def_descr_article(def_id);
-    let desc = cx.tcx.def_descr(def_id);
-    cx.emit_spanned_lint(
-        USELESS_ANONYMOUS_REEXPORT,
-        span,
-        UselessAnonymousReexportDiag { article, desc },
-    );
-}
-
-impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if let ItemKind::Use(path, kind) = item.kind &&
-            !matches!(kind, UseKind::Glob) &&
-            item.ident.name == kw::Underscore &&
-            // We only want re-exports. If it's just a `use X;`, then we ignore it.
-            match cx.tcx.local_visibility(item.owner_id.def_id) {
-                Visibility::Public => true,
-                Visibility::Restricted(level) => {
-                    level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
-                }
-            }
-        {
-            for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) {
-                match cx.tcx.def_kind(def_id) {
-                    DefKind::Trait | DefKind::TraitAlias => {}
-                    DefKind::TyAlias => {
-                        let ty = cx.tcx.type_of(def_id);
-                        if !ty.0.is_trait() {
-                            emit_err(cx, item.span, def_id);
-                            break;
-                        }
-                    }
-                    _ => {
-                        emit_err(cx, item.span, def_id);
-                        break;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 91966e75b5f..9d6ab0b75df 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3230,6 +3230,45 @@ declare_lint! {
     };
 }
 
+declare_lint! {
+    /// The `ambiguous_glob_reexports` lint detects cases where names re-exported via globs
+    /// collide. Downstream users trying to use the same name re-exported from multiple globs
+    /// will receive a warning pointing out redefinition of the same name.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(ambiguous_glob_reexports)]
+    /// pub mod foo {
+    ///     pub type X = u8;
+    /// }
+    ///
+    /// pub mod bar {
+    ///     pub type Y = u8;
+    ///     pub type X = u8;
+    /// }
+    ///
+    /// pub use foo::*;
+    /// pub use bar::*;
+    ///
+    ///
+    /// pub fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This was previously accepted but it could silently break a crate's downstream users code.
+    /// For example, if `foo::*` and `bar::*` were re-exported before `bar::X` was added to the
+    /// re-exports, down stream users could use `this_crate::X` without problems. However, adding
+    /// `bar::X` would cause compilation errors in downstream crates because `X` is defined
+    /// multiple times in the same namespace of `this_crate`.
+    pub AMBIGUOUS_GLOB_REEXPORTS,
+    Warn,
+    "ambiguous glob re-exports",
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -3337,6 +3376,7 @@ declare_lint_pass! {
         NAMED_ARGUMENTS_USED_POSITIONALLY,
         IMPLIED_BOUNDS_ENTAILMENT,
         BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+        AMBIGUOUS_GLOB_REEXPORTS,
     ]
 }
 
@@ -3968,14 +4008,9 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,ignore (need FFI)
-    /// #![feature(ffi_unwind_calls)]
+    /// ```rust
     /// #![feature(c_unwind)]
-    ///
-    /// # mod impl {
-    /// #     #[no_mangle]
-    /// #     pub fn "C-unwind" fn foo() {}
-    /// # }
+    /// #![warn(ffi_unwind_calls)]
     ///
     /// extern "C-unwind" {
     ///     fn foo();
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 6f22bdabff4..69a8b691ab2 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -529,6 +529,16 @@ pub enum BuiltinLintDiagnostics {
         vis_span: Span,
         ident_span: Span,
     },
+    AmbiguousGlobReexports {
+        /// The name for which collision(s) have occurred.
+        name: String,
+        /// The name space for whihc the collision(s) occurred in.
+        namespace: String,
+        /// Span where the name is first re-exported.
+        first_reexport_span: Span,
+        /// Span where the same name is also re-exported.
+        duplicate_reexport_span: Span,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index bee5c8541d6..4d7c133e09b 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index c48e681eb94..79c42a128e7 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -222,6 +222,7 @@ use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
+use rustc_fs_util::try_canonicalize;
 use rustc_session::config::{self, CrateType};
 use rustc_session::cstore::{CrateSource, MetadataLoader};
 use rustc_session::filesearch::FileSearch;
@@ -236,7 +237,7 @@ use snap::read::FrameDecoder;
 use std::borrow::Cow;
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
-use std::{cmp, fmt, fs};
+use std::{cmp, fmt};
 
 #[derive(Clone)]
 pub(crate) struct CrateLocator<'a> {
@@ -441,7 +442,7 @@ impl<'a> CrateLocator<'a> {
                 info!("lib candidate: {}", spf.path.display());
 
                 let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
-                let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
+                let path = try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
                 if seen_paths.contains(&path) {
                     continue;
                 };
@@ -636,7 +637,7 @@ impl<'a> CrateLocator<'a> {
             // as well.
             if let Some((prev, _)) = &ret {
                 let sysroot = self.sysroot;
-                let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
+                let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());
                 if prev.starts_with(&sysroot) {
                     continue;
                 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index cabc144077f..06a64f0db0e 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -925,10 +925,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         tcx.mk_adt_def(did, adt_kind, variants, repr)
     }
 
-    fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
-        self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess))
-    }
-
     fn get_visibility(self, id: DefIndex) -> Visibility<DefId> {
         self.root
             .tables
@@ -1045,13 +1041,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.optimized_mir.get(self, id).is_some()
     }
 
-    fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
-        match self.def_kind(id) {
-            DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess),
-            _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
-        }
-    }
-
     fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
         self.root
             .tables
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index caff01498d9..3a50d7c9363 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -490,6 +490,9 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
         },
         crates: |tcx, ()| {
+            // The list of loaded crates is now frozen in query cache,
+            // so make sure cstore is not mutably accessed from here on.
+            tcx.untracked().cstore.leak();
             tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum))
         },
         ..*providers
@@ -537,20 +540,16 @@ impl CStore {
         )
     }
 
-    pub fn get_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
+    pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
         self.get_crate_data(def_id.krate).get_span(def_id.index, sess)
     }
 
-    pub fn def_kind(&self, def: DefId) -> DefKind {
+    pub fn def_kind_untracked(&self, def: DefId) -> DefKind {
         self.get_crate_data(def.krate).def_kind(def.index)
     }
 
-    pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
-        self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
-    }
-
-    pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
-        self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
+    pub fn expn_that_defined_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
+        self.get_crate_data(def_id.krate).get_expn_that_defined(def_id.index, sess)
     }
 
     /// Only public-facing way to traverse all the definitions in a non-local crate.
@@ -560,14 +559,6 @@ impl CStore {
         self.get_crate_data(cnum).num_def_ids()
     }
 
-    pub fn item_attrs_untracked<'a>(
-        &'a self,
-        def_id: DefId,
-        sess: &'a Session,
-    ) -> impl Iterator<Item = ast::Attribute> + 'a {
-        self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess)
-    }
-
     pub fn get_proc_macro_quoted_span_untracked(
         &self,
         cnum: CrateNum,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 0b438d1ffad..2652a4280d3 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -27,7 +27,7 @@ use rustc_middle::mir::interpret;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
@@ -1881,7 +1881,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         self.tcx,
                         trait_ref.self_ty(),
                         TreatParams::AsCandidateKey,
-                        TreatProjections::AsCandidateKey,
                     );
 
                     fx_hash_map
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 72907fba5e6..9f16ecbdaa9 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -36,7 +36,7 @@ macro_rules! arena_types {
             )>,
             [] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>,
             [] metadata_loader: rustc_data_structures::steal::Steal<Box<rustc_session::cstore::MetadataLoaderDyn>>,
-            [] crate_for_resolver: rustc_data_structures::steal::Steal<rustc_ast::ast::Crate>,
+            [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>,
             [] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
             [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 638c082cc84..9c575f6eb9f 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1967,7 +1967,8 @@ impl<'tcx> Rvalue<'tcx> {
                 | CastKind::PtrToPtr
                 | CastKind::Pointer(_)
                 | CastKind::PointerFromExposedAddress
-                | CastKind::DynStar,
+                | CastKind::DynStar
+                | CastKind::Transmute,
                 _,
                 _,
             )
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 3a893cdabf6..bbd913d071d 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1156,6 +1156,13 @@ pub enum CastKind {
     IntToFloat,
     PtrToPtr,
     FnPtrToPtr,
+    /// Reinterpret the bits of the input as a different type.
+    ///
+    /// MIR is well-formed if the input and output types have different sizes,
+    /// but running a transmute between differently-sized types is UB.
+    ///
+    /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`].
+    Transmute,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index f740ec51080..9203dd59a7e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2116,7 +2116,7 @@ rustc_queries! {
         desc { "raw operations for metadata file access" }
     }
 
-    query crate_for_resolver((): ()) -> &'tcx Steal<rustc_ast::ast::Crate> {
+    query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> {
         feedable
         no_hash
         desc { "the ast before macro expansion and name resolution" }
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index ee505742be9..669d50a7fda 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -56,7 +56,15 @@ pub enum TreatParams {
     AsCandidateKey,
     /// Treat parameters as placeholders in the given environment. This is the
     /// correct mode for *lookup*, as during candidate selection.
+    ///
+    /// This also treats projections with inference variables as infer vars
+    /// since they could be further normalized.
     ForLookup,
+    /// Treat parameters as placeholders in the given environment. This is the
+    /// correct mode for *lookup*, as during candidate selection.
+    ///
+    /// N.B. during deep rejection, this acts identically to `ForLookup`.
+    NextSolverLookup,
 }
 
 /// During fast-rejection, we have the choice of treating projection types
@@ -64,13 +72,6 @@ pub enum TreatParams {
 /// to be normalized/rigid.
 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
 pub enum TreatProjections {
-    /// In candidates, we may be able to normalize the projection
-    /// after instantiating the candidate and equating it with a goal.
-    ///
-    /// We must assume that the `impl<T> Trait<T> for <T as Id>::This`
-    /// can apply to all self types so we don't return a simplified type
-    /// for `<T as Id>::This`.
-    AsCandidateKey,
     /// In the old solver we don't try to normalize projections
     /// when looking up impls and only access them by using the
     /// current self type. This means that if the self type is
@@ -107,7 +108,6 @@ pub fn simplify_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     treat_params: TreatParams,
-    treat_projections: TreatProjections,
 ) -> Option<SimplifiedType> {
     match *ty.kind() {
         ty::Bool => Some(BoolSimplifiedType),
@@ -136,13 +136,20 @@ pub fn simplify_type<'tcx>(
         ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
         ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
         ty::Param(_) => match treat_params {
-            TreatParams::ForLookup => Some(PlaceholderSimplifiedType),
+            TreatParams::ForLookup | TreatParams::NextSolverLookup => {
+                Some(PlaceholderSimplifiedType)
+            }
             TreatParams::AsCandidateKey => None,
         },
-        ty::Alias(..) => match treat_projections {
-            TreatProjections::ForLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType),
-            TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType),
-            TreatProjections::AsCandidateKey | TreatProjections::ForLookup => None,
+        ty::Alias(..) => match treat_params {
+            // When treating `ty::Param` as a placeholder, projections also
+            // don't unify with anything else as long as they are fully normalized.
+            //
+            // We will have to be careful with lazy normalization here.
+            // FIXME(lazy_normalization): This is probably not right...
+            TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType),
+            TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType),
+            TreatParams::ForLookup | TreatParams::AsCandidateKey => None,
         },
         ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
         ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
@@ -310,7 +317,7 @@ impl DeepRejectCtxt {
             // Depending on the value of `treat_obligation_params`, we either
             // treat generic parameters like placeholders or like inference variables.
             ty::Param(_) => match self.treat_obligation_params {
-                TreatParams::ForLookup => false,
+                TreatParams::ForLookup | TreatParams::NextSolverLookup => false,
                 TreatParams::AsCandidateKey => true,
             },
 
@@ -348,7 +355,7 @@ impl DeepRejectCtxt {
         let k = impl_ct.kind();
         match obligation_ct.kind() {
             ty::ConstKind::Param(_) => match self.treat_obligation_params {
-                TreatParams::ForLookup => false,
+                TreatParams::ForLookup | TreatParams::NextSolverLookup => false,
                 TreatParams::AsCandidateKey => true,
             },
 
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 91241ff404f..5a6ee123811 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -288,7 +288,7 @@ impl FlagComputation {
                 self.add_ty(ty);
             }
             ty::PredicateKind::Ambiguous => {}
-            ty::PredicateKind::AliasEq(t1, t2) => {
+            ty::PredicateKind::AliasRelate(t1, t2, _) => {
                 self.add_term(t1);
                 self.add_term(t2);
             }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9b0c6e25d16..e3cd5cca785 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -543,7 +543,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(Clause::TypeOutlives(_))
             | PredicateKind::Clause(Clause::Projection(_))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::ObjectSafe(_)
             | PredicateKind::ClosureKind(_, _, _)
             | PredicateKind::Subtype(_)
@@ -640,7 +640,23 @@ pub enum PredicateKind<'tcx> {
     /// This predicate requires two terms to be equal to eachother.
     ///
     /// Only used for new solver
-    AliasEq(Term<'tcx>, Term<'tcx>),
+    AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable, Debug)]
+pub enum AliasRelationDirection {
+    Equate,
+    Subtype,
+}
+
+impl std::fmt::Display for AliasRelationDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            AliasRelationDirection::Equate => write!(f, " == "),
+            AliasRelationDirection::Subtype => write!(f, " <: "),
+        }
+    }
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -976,11 +992,11 @@ impl<'tcx> Term<'tcx> {
         }
     }
 
-    /// This function returns `None` for `AliasKind::Opaque`.
+    /// This function returns the inner `AliasTy` if this term is a projection.
     ///
     /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
     /// deal with constants.
-    pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
+    pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
         match self.unpack() {
             TermKind::Ty(ty) => match ty.kind() {
                 ty::Alias(kind, alias_ty) => match kind {
@@ -1035,6 +1051,21 @@ impl<'tcx> TermKind<'tcx> {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum ParamTerm {
+    Ty(ParamTy),
+    Const(ParamConst),
+}
+
+impl ParamTerm {
+    pub fn index(self) -> usize {
+        match self {
+            ParamTerm::Ty(ty) => ty.index as usize,
+            ParamTerm::Const(ct) => ct.index as usize,
+        }
+    }
+}
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -1206,7 +1237,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(Clause::Projection(..))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -1227,7 +1258,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(Clause::Trait(..))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -1249,7 +1280,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::Trait(..))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
             | PredicateKind::Clause(Clause::Projection(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fffdbfc9660..de4c703107e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -704,7 +704,11 @@ pub trait PrettyPrinter<'tcx>:
                 ty::BoundTyKind::Anon(bv) => {
                     self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))?
                 }
-                ty::BoundTyKind::Param(_, s) => p!(write("{}", s)),
+                ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() {
+                    true if debruijn == ty::INNERMOST => p!(write("^{}", s)),
+                    true => p!(write("^{}_{}", debruijn.index(), s)),
+                    false => p!(write("{}", s)),
+                },
             },
             ty::Adt(def, substs) => {
                 p!(print_def_path(def.did(), substs));
@@ -2847,7 +2851,7 @@ define_print_and_forward_display! {
                 p!("the type `", print(ty), "` is found in the environment")
             }
             ty::PredicateKind::Ambiguous => p!("ambiguous"),
-            ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)),
+            ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index ef643531bb2..c6bb8146795 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
             }
             ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
-            ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"),
+            ty::PredicateKind::AliasRelate(t1, t2, dir) => {
+                write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
+            }
         }
     }
 }
@@ -250,6 +252,7 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::AssocItem,
     crate::ty::AssocKind,
     crate::ty::AliasKind,
+    crate::ty::AliasRelationDirection,
     crate::ty::Placeholder<crate::ty::BoundRegionKind>,
     crate::ty::Placeholder<crate::ty::BoundTyKind>,
     crate::ty::ClosureKind,
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index bf2b121f704..6747da7abd3 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -153,12 +153,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self_ty: Ty<'tcx>,
     ) -> impl Iterator<Item = DefId> + 'tcx {
         let impls = self.trait_impls_of(trait_def_id);
-        if let Some(simp) = fast_reject::simplify_type(
-            self,
-            self_ty,
-            TreatParams::AsCandidateKey,
-            TreatProjections::AsCandidateKey,
-        ) {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 return impls.iter().copied();
             }
@@ -191,13 +186,17 @@ impl<'tcx> TyCtxt<'tcx> {
             }
         }
 
+        // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
+        // `TreatParams::AsCandidateKey` while actually adding them.
+        let treat_params = match treat_projections {
+            TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup,
+            TreatProjections::ForLookup => TreatParams::ForLookup,
+        };
         // This way, when searching for some impl for `T: Trait`, we do not look at any impls
         // whose outer level is not a parameter or projection. Especially for things like
         // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
         // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
-        if let Some(simp) =
-            fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup, treat_projections)
-        {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
                     if let result @ Some(_) = f(impl_def_id) {
@@ -258,12 +257,9 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
             continue;
         }
 
-        if let Some(simplified_self_ty) = fast_reject::simplify_type(
-            tcx,
-            impl_self_ty,
-            TreatParams::AsCandidateKey,
-            TreatProjections::AsCandidateKey,
-        ) {
+        if let Some(simplified_self_ty) =
+            fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey)
+        {
             impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
         } else {
             impls.blanket_impls.push(impl_def_id);
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index adbd37a7cd9..bf58b3090fb 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -137,6 +137,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, expr, "rvalue",
             @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
+            @call("mir_cast_transmute", args) => {
+                let source = self.parse_operand(args[0])?;
+                Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
+            },
             @call("mir_checked", args) => {
                 parse_by_kind!(self, args[0], _, "binary op",
                     ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 140d1154718..3b775f590a4 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -566,41 +566,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Rvalue::Use(Operand::Move(val))
             }
             BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => {
-                // Consider that the shift overflows if `rhs < 0` or `rhs >= bits`.
-                // This can be encoded as a single operation as `(rhs & -bits) != 0`.
-                let (size, _) = ty.int_size_and_signed(self.tcx);
-                let bits = size.bits();
-                debug_assert!(bits.is_power_of_two());
-                let mask = !((bits - 1) as u128);
-
+                // For an unsigned RHS, the shift is in-range for `rhs < bits`.
+                // For a signed RHS, `IntToInt` cast to the equivalent unsigned
+                // type and do that same comparison.  Because the type is the
+                // same size, there's no negative shift amount that ends up
+                // overlapping with valid ones, thus it catches negatives too.
+                let (lhs_size, _) = ty.int_size_and_signed(self.tcx);
                 let rhs_ty = rhs.ty(&self.local_decls, self.tcx);
                 let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx);
-                let mask = Operand::const_from_scalar(
+
+                let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() {
+                    ty::Uint(_) => (rhs.to_copy(), rhs_ty),
+                    ty::Int(int_width) => {
+                        let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned());
+                        let rhs_temp = self.temp(uint_ty, span);
+                        self.cfg.push_assign(
+                            block,
+                            source_info,
+                            rhs_temp,
+                            Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty),
+                        );
+                        (Operand::Move(rhs_temp), uint_ty)
+                    }
+                    _ => unreachable!("only integers are shiftable"),
+                };
+
+                // This can't overflow because the largest shiftable types are 128-bit,
+                // which fits in `u8`, the smallest possible `unsigned_ty`.
+                // (And `from_uint` will `bug!` if that's ever no longer true.)
+                let lhs_bits = Operand::const_from_scalar(
                     self.tcx,
-                    rhs_ty,
-                    Scalar::from_uint(rhs_size.truncate(mask), rhs_size),
+                    unsigned_ty,
+                    Scalar::from_uint(lhs_size.bits(), rhs_size),
                     span,
                 );
 
-                let outer_bits = self.temp(rhs_ty, span);
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    outer_bits,
-                    Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))),
-                );
-
-                let overflows = self.temp(bool_ty, span);
-                let zero = self.zero_literal(span, rhs_ty);
+                let inbounds = self.temp(bool_ty, span);
                 self.cfg.push_assign(
                     block,
                     source_info,
-                    overflows,
-                    Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))),
+                    inbounds,
+                    Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))),
                 );
 
                 let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
-                block = self.assert(block, Operand::Move(overflows), false, overflow_err, span);
+                block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span);
                 Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
             }
             BinOp::Div | BinOp::Rem if ty.is_integral() => {
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 8b81abb23b0..c1cf6ee0f9e 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -504,6 +504,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
                 return None;
             }
+            // Do not try creating references, nor any types with potentially-complex
+            // invariants. This avoids an issue where checking validity would do a
+            // bunch of work generating a nice message about the invariant violation,
+            // only to not show it to anyone (since this isn't the lint).
+            Rvalue::Cast(CastKind::Transmute, op, dst_ty) if !dst_ty.is_primitive() => {
+                trace!("skipping Transmute of {:?} to {:?}", op, dst_ty);
+
+                return None;
+            }
 
             // There's no other checking to do at this time.
             Rvalue::Aggregate(..)
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 46eab1184bd..6a7ceb8fef7 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -221,6 +221,32 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             terminator.kind = TerminatorKind::Goto { target };
                         }
                     }
+                    sym::transmute => {
+                        let dst_ty = destination.ty(local_decls, tcx).ty;
+                        let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else {
+                            span_bug!(
+                                terminator.source_info.span,
+                                "Wrong number of arguments for transmute intrinsic",
+                            );
+                        };
+
+                        // Always emit the cast, even if we transmute to an uninhabited type,
+                        // because that lets CTFE and codegen generate better error messages
+                        // when such a transmute actually ends up reachable.
+                        block.statements.push(Statement {
+                            source_info: terminator.source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                *destination,
+                                Rvalue::Cast(CastKind::Transmute, arg, dst_ty),
+                            ))),
+                        });
+
+                        if let Some(target) = *target {
+                            terminator.kind = TerminatorKind::Goto { target };
+                        } else {
+                            terminator.kind = TerminatorKind::Unreachable;
+                        }
+                    }
                     _ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
                         validate_simd_shuffle(tcx, args, terminator.source_info.span);
                     }
diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs
index 8e75e969ae0..27e5cb9f0d0 100644
--- a/compiler/rustc_plugin_impl/src/load.rs
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -3,7 +3,7 @@
 use crate::errors::{LoadPluginError, MalformedPluginAttribute};
 use crate::Registry;
 use libloading::Library;
-use rustc_ast::Crate;
+use rustc_ast::Attribute;
 use rustc_metadata::locator;
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::Session;
@@ -20,11 +20,11 @@ type PluginRegistrarFn = fn(&mut Registry<'_>);
 pub fn load_plugins(
     sess: &Session,
     metadata_loader: &dyn MetadataLoader,
-    krate: &Crate,
+    attrs: &[Attribute],
 ) -> Vec<PluginRegistrarFn> {
     let mut plugins = Vec::new();
 
-    for attr in &krate.attrs {
+    for attr in attrs {
         if !attr.has_name(sym::plugin) {
             continue;
         }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index d884ebd9acc..3be0160d561 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -180,7 +180,7 @@ where
             | ty::PredicateKind::ConstEquate(_, _)
             | ty::PredicateKind::TypeWellFormedFromEnv(_)
             | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate),
+            | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate),
         }
     }
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index f79807fee39..19ccb3a6484 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -27,7 +27,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::{bug, ty};
-use rustc_session::cstore::CrateStore;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -115,34 +114,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         if !def_id.is_local() {
-            let def_kind = self.cstore().def_kind(def_id);
-            match def_kind {
-                DefKind::Mod | DefKind::Enum | DefKind::Trait => {
-                    let def_key = self.cstore().def_key(def_id);
-                    let parent = def_key.parent.map(|index| {
-                        self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
-                    });
-                    let name = if let Some(cnum) = def_id.as_crate_root() {
-                        self.cstore().crate_name(cnum)
-                    } else {
-                        def_key.disambiguated_data.data.get_opt_name().expect("module without name")
-                    };
-
-                    let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess);
-                    Some(self.new_module(
-                        parent,
-                        ModuleKind::Def(def_kind, def_id, name),
-                        expn_id,
-                        self.def_span(def_id),
-                        // FIXME: Account for `#[no_implicit_prelude]` attributes.
-                        parent.map_or(false, |module| module.no_implicit_prelude),
-                    ))
-                }
-                _ => None,
+            // Query `def_kind` is not used because query system overhead is too expensive here.
+            let def_kind = self.cstore().def_kind_untracked(def_id);
+            if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind {
+                let parent = self
+                    .tcx
+                    .opt_parent(def_id)
+                    .map(|parent_id| self.get_nearest_non_block_module(parent_id));
+                // Query `expn_that_defined` is not used because
+                // hashing spans in its result is expensive.
+                let expn_id = self.cstore().expn_that_defined_untracked(def_id, &self.tcx.sess);
+                return Some(self.new_module(
+                    parent,
+                    ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)),
+                    expn_id,
+                    self.def_span(def_id),
+                    // FIXME: Account for `#[no_implicit_prelude]` attributes.
+                    parent.map_or(false, |module| module.no_implicit_prelude),
+                ));
             }
-        } else {
-            None
         }
+
+        None
     }
 
     pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
@@ -204,6 +197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) {
+        // Query `module_children` is not used because hashing spans in its result is expensive.
         let children =
             Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess));
         for child in children {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index b2578e4c4b4..dbf6cec788b 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
+use rustc_hir::def::{DefKind, Res};
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, DUMMY_SP};
 
 struct UnusedImport<'a> {
@@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
     item_span: Span,
+    base_use_is_pub: bool,
 }
 
 struct ExternCrateToLint {
@@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             unused: Default::default(),
         })
     }
+
+    fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) {
+        match item.kind {
+            ast::UseTreeKind::Simple(Some(ident)) => {
+                if ident.name == kw::Underscore
+                    && !self
+                        .r
+                        .import_res_map
+                        .get(&id)
+                        .map(|per_ns| {
+                            per_ns.iter().filter_map(|res| res.as_ref()).any(|res| {
+                                matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
+                            })
+                        })
+                        .unwrap_or(false)
+                {
+                    self.unused_import(self.base_id).add(id);
+                }
+            }
+            ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items),
+            _ => {}
+        }
+    }
+
+    fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) {
+        for (item, id) in items {
+            self.check_import_as_underscore(item, *id);
+        }
+    }
 }
 
 impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
@@ -119,7 +150,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             // whether they're used or not. Also ignore imports with a dummy span
             // because this means that they were generated in some fashion by the
             // compiler and we don't need to consider them.
-            ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return,
+            ast::ItemKind::Use(..) if item.span.is_dummy() => return,
+            ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(),
             ast::ItemKind::ExternCrate(orig_name) => {
                 self.extern_crate_items.push(ExternCrateToLint {
                     id: item.id,
@@ -146,6 +178,11 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             self.base_use_tree = Some(use_tree);
         }
 
+        if self.base_use_is_pub {
+            self.check_import_as_underscore(use_tree, id);
+            return;
+        }
+
         if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
             if items.is_empty() {
                 self.unused_import(self.base_id).add(id);
@@ -300,6 +337,7 @@ impl Resolver<'_, '_> {
             base_use_tree: None,
             base_id: ast::DUMMY_NODE_ID,
             item_span: DUMMY_SP,
+            base_use_is_pub: false,
         };
         visit::walk_crate(&mut visitor, krate);
 
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 4bb252bfb29..a1ae9b8a521 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -4,6 +4,7 @@ use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
 use rustc_ast::Crate;
 use rustc_ast::EnumDef;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
@@ -70,11 +71,11 @@ impl Resolver<'_, '_> {
 impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
     /// Fills the `Resolver::effective_visibilities` table with public & exported items
     /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
-    /// need access to a TyCtxt for that.
+    /// need access to a TyCtxt for that. Returns the set of ambiguous re-exports.
     pub(crate) fn compute_effective_visibilities<'c>(
         r: &'r mut Resolver<'a, 'tcx>,
         krate: &'c Crate,
-    ) {
+    ) -> FxHashSet<Interned<'a, NameBinding<'a>>> {
         let mut visitor = EffectiveVisibilitiesVisitor {
             r,
             def_effective_visibilities: Default::default(),
@@ -93,18 +94,26 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         }
         visitor.r.effective_visibilities = visitor.def_effective_visibilities;
 
+        let mut exported_ambiguities = FxHashSet::default();
+
         // Update visibilities for import def ids. These are not used during the
         // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
         // information, but are used by later passes. Effective visibility of an import def id
         // is the maximum value among visibilities of bindings corresponding to that def id.
         for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
             let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
-            if let Some(node_id) = import.id() {
-                r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
+            if !binding.is_ambiguity() {
+                if let Some(node_id) = import.id() {
+                    r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
+                }
+            } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) {
+                exported_ambiguities.insert(*binding);
             }
         }
 
         info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
+
+        exported_ambiguities
     }
 
     /// Update effective visibilities of bindings in the given module,
@@ -115,21 +124,44 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         let resolutions = self.r.resolutions(module);
 
         for (_, name_resolution) in resolutions.borrow().iter() {
-            if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
-                // Set the given effective visibility level to `Level::Direct` and
-                // sets the rest of the `use` chain to `Level::Reexported` until
-                // we hit the actual exported item.
-                let mut parent_id = ParentId::Def(module_id);
-                while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
-                    let binding_id = ImportId::new_unchecked(binding);
-                    self.update_import(binding_id, parent_id);
-
-                    parent_id = ParentId::Import(binding_id);
-                    binding = nested_binding;
-                }
+            if let Some(mut binding) = name_resolution.borrow().binding() {
+                if !binding.is_ambiguity() {
+                    // Set the given effective visibility level to `Level::Direct` and
+                    // sets the rest of the `use` chain to `Level::Reexported` until
+                    // we hit the actual exported item.
+                    let mut parent_id = ParentId::Def(module_id);
+                    while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
+                    {
+                        let binding_id = ImportId::new_unchecked(binding);
+                        self.update_import(binding_id, parent_id);
+
+                        parent_id = ParentId::Import(binding_id);
+                        binding = nested_binding;
+                    }
+
+                    if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+                        self.update_def(def_id, binding.vis.expect_local(), parent_id);
+                    }
+                } else {
+                    // Put the root ambiguity binding and all reexports leading to it into the
+                    // table. They are used by the `ambiguous_glob_reexports` lint. For all
+                    // bindings added to the table here `is_ambiguity` returns true.
+                    let mut parent_id = ParentId::Def(module_id);
+                    while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
+                    {
+                        let binding_id = ImportId::new_unchecked(binding);
+                        self.update_import(binding_id, parent_id);
 
-                if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
-                    self.update_def(def_id, binding.vis.expect_local(), parent_id);
+                        if binding.ambiguity.is_some() {
+                            // Stop at the root ambiguity, further bindings in the chain should not
+                            // be reexported because the root ambiguity blocks any access to them.
+                            // (Those further bindings are most likely not ambiguities themselves.)
+                            break;
+                        }
+
+                        parent_id = ParentId::Import(binding_id);
+                        binding = nested_binding;
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4d4bc1be349..bc17ce571a7 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -19,7 +19,9 @@ use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
-use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{
+    AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS,
+};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::LocalExpnId;
@@ -510,6 +512,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
+    pub(crate) fn check_reexport_ambiguities(
+        &mut self,
+        exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>,
+    ) {
+        for module in self.arenas.local_modules().iter() {
+            module.for_each_child(self, |this, ident, ns, binding| {
+                if let NameBindingKind::Import { import, .. } = binding.kind
+                && let Some((amb_binding, _)) = binding.ambiguity
+                && binding.res() != Res::Err
+                && exported_ambiguities.contains(&Interned::new_unchecked(binding))
+                {
+                    this.lint_buffer.buffer_lint_with_diagnostic(
+                        AMBIGUOUS_GLOB_REEXPORTS,
+                        import.root_id,
+                        import.root_span,
+                        "ambiguous glob re-exports",
+                        BuiltinLintDiagnostics::AmbiguousGlobReexports {
+                            name: ident.to_string(),
+                            namespace: ns.descr().to_string(),
+                            first_reexport_span: import.root_span,
+                            duplicate_reexport_span: amb_binding.span,
+                        },
+                    );
+                }
+            });
+        }
+    }
+
     fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
         if errors.is_empty() {
             return;
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index a0b9188c315..0e84432a5b4 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1168,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
         if let Some(def_id) = def_id.as_local() {
             self.item_generics_num_lifetimes[&def_id]
         } else {
-            self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess)
+            self.tcx.generics_of(def_id).own_counts().lifetimes
         }
     }
 
@@ -1180,7 +1180,8 @@ impl<'tcx> Resolver<'_, 'tcx> {
 impl<'a, 'tcx> Resolver<'a, 'tcx> {
     pub fn new(
         tcx: TyCtxt<'tcx>,
-        krate: &Crate,
+        attrs: &[ast::Attribute],
+        crate_span: Span,
         arenas: &'a ResolverArenas<'a>,
     ) -> Resolver<'a, 'tcx> {
         let root_def_id = CRATE_DEF_ID.to_def_id();
@@ -1189,8 +1190,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             None,
             ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
             ExpnId::root(),
-            krate.spans.inner_span,
-            attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
+            crate_span,
+            attr::contains_name(attrs, sym::no_implicit_prelude),
             &mut module_map,
         );
         let empty_module = arenas.new_module(
@@ -1222,9 +1223,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             .map(|(name, _)| (Ident::from_str(name), Default::default()))
             .collect();
 
-        if !attr::contains_name(&krate.attrs, sym::no_core) {
+        if !attr::contains_name(attrs, sym::no_core) {
             extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
-            if !attr::contains_name(&krate.attrs, sym::no_std) {
+            if !attr::contains_name(attrs, sym::no_std) {
                 extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
             }
         }
@@ -1474,9 +1475,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     pub fn resolve_crate(&mut self, krate: &Crate) {
         self.tcx.sess.time("resolve_crate", || {
             self.tcx.sess.time("finalize_imports", || self.finalize_imports());
-            self.tcx.sess.time("compute_effective_visibilities", || {
+            let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
                 EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
             });
+            self.tcx.sess.time("check_reexport_ambiguities", || {
+                self.check_reexport_ambiguities(exported_ambiguities)
+            });
             self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
             self.tcx.sess.time("resolve_main", || self.resolve_main());
@@ -1871,7 +1875,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     fn def_span(&self, def_id: DefId) -> Span {
         match def_id.as_local() {
             Some(def_id) => self.tcx.source_span(def_id),
-            None => self.cstore().get_span_untracked(def_id, self.tcx.sess),
+            // Query `def_span` is not used because hashing its result span is expensive.
+            None => self.cstore().def_span_untracked(def_id, self.tcx.sess),
         }
     }
 
@@ -1906,10 +1911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     return v.clone();
                 }
 
-                let attr = self
-                    .cstore()
-                    .item_attrs_untracked(def_id, self.tcx.sess)
-                    .find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
+                let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?;
                 let mut ret = Vec::new();
                 for meta in attr.meta_item_list()? {
                     match meta.lit()?.kind {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index c540682d8db..48707d37a10 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -112,8 +112,8 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
 
 pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
     let mut registered_tools = RegisteredTools::default();
-    let krate = tcx.crate_for_resolver(()).borrow();
-    for attr in attr::filter_by_name(&krate.attrs, sym::register_tool) {
+    let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow();
+    for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) {
         for nested_meta in attr.meta_item_list().unwrap_or_default() {
             match nested_meta.ident() {
                 Some(ident) => {
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index e734599cbfc..2404928b254 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -1,5 +1,6 @@
 //! A module for searching for libraries
 
+use rustc_fs_util::try_canonicalize;
 use smallvec::{smallvec, SmallVec};
 use std::env;
 use std::fs;
@@ -125,7 +126,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
     let target = crate::config::host_triple();
     let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
         smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
-    let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string()));
+    let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string()));
     if let Ok(dll) = path {
         // use `parent` twice to chop off the file name and then also the
         // directory containing the dll which should be either `lib` or `bin`.
@@ -160,7 +161,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
 pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
     // Follow symlinks. If the resolved path is relative, make it absolute.
     fn canonicalize(path: PathBuf) -> PathBuf {
-        let path = fs::canonicalize(&path).unwrap_or(path);
+        let path = try_canonicalize(&path).unwrap_or(path);
         // See comments on this target function, but the gist is that
         // gcc chokes on verbatim paths which fs::canonicalize generates
         // so we try to avoid those kinds of paths.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 0548379dc2f..c75af48e80a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -4,6 +4,7 @@ use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
+use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{LanguageIdentifier, TerminalUrl};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{
@@ -365,6 +366,7 @@ mod desc {
     pub const parse_number: &str = "a number";
     pub const parse_opt_number: &str = parse_number;
     pub const parse_threads: &str = parse_number;
+    pub const parse_time_passes_format: &str = "`text` (default) or `json`";
     pub const parse_passes: &str = "a space-separated list of passes, or `all`";
     pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
@@ -829,6 +831,21 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
+        match v {
+            None => true,
+            Some("json") => {
+                *slot = TimePassesFormat::Json;
+                true
+            }
+            Some("text") => {
+                *slot = TimePassesFormat::Text;
+                true
+            }
+            Some(_) => false,
+        }
+    }
+
     pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
         match v {
             None => true,
@@ -1709,6 +1726,8 @@ options! {
         "measure time of each LLVM pass (default: no)"),
     time_passes: bool = (false, parse_bool, [UNTRACKED],
         "measure time of each rustc pass (default: no)"),
+    time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
+        "the format to use for -Z time-passes (`text` (default) or `json`)"),
     tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
         "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
     #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 700a059c368..5730df9d5c6 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1453,7 +1453,10 @@ pub fn build_session(
         CguReuseTracker::new_disabled()
     };
 
-    let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes);
+    let prof = SelfProfilerRef::new(
+        self_profiler,
+        sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
+    );
 
     let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
         Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 3b3d4ca5d6b..1d15e2c28d8 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,5 +1,6 @@
 use crate::session::Session;
 use rustc_data_structures::profiling::VerboseTimingGuard;
+use rustc_fs_util::try_canonicalize;
 use std::path::{Path, PathBuf};
 
 impl Session {
@@ -98,7 +99,7 @@ pub struct CanonicalizedPath {
 
 impl CanonicalizedPath {
     pub fn new(path: &Path) -> Self {
-        Self { original: path.to_owned(), canonicalized: std::fs::canonicalize(path).ok() }
+        Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() }
     }
 
     pub fn canonicalized(&self) -> &PathBuf {
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 568c916a163..4e7a8d166ae 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 bitflags = "1.2.1"
 tracing = "0.1"
 serde_json = "1.0.59"
+rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f3304e91429..2553b11d878 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -40,6 +40,7 @@ use crate::json::{Json, ToJson};
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_fs_util::try_canonicalize;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::symbol::{sym, Symbol};
 use serde_json::Value;
@@ -2949,7 +2950,7 @@ impl TargetTriple {
 
     /// Creates a target triple from the passed target path.
     pub fn from_path(path: &Path) -> Result<Self, io::Error> {
-        let canonicalized_path = path.canonicalize()?;
+        let canonicalized_path = try_canonicalize(path)?;
         let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
             io::Error::new(
                 io::ErrorKind::InvalidInput,
diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs
index 9d45e78ebab..efecaf33ef9 100644
--- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs
@@ -99,20 +99,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         original_values: Vec<ty::GenericArg<'tcx>>,
         response: CanonicalResponse<'tcx>,
-    ) -> Result<Certainty, NoSolution> {
+    ) -> Result<(Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
         let substitution = self.compute_query_response_substitution(&original_values, &response);
 
         let Response { var_values, external_constraints, certainty } =
             response.substitute(self.tcx(), &substitution);
 
-        self.unify_query_var_values(param_env, &original_values, var_values)?;
+        let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?;
 
         // FIXME: implement external constraints.
         let ExternalConstraintsData { region_constraints, opaque_types: _ } =
             external_constraints.deref();
         self.register_region_constraints(region_constraints);
 
-        Ok(certainty)
+        Ok((certainty, nested_goals))
     }
 
     /// This returns the substitutions to instantiate the bound variables of
@@ -205,21 +205,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         original_values: &[ty::GenericArg<'tcx>],
         var_values: CanonicalVarValues<'tcx>,
-    ) -> Result<(), NoSolution> {
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
         assert_eq!(original_values.len(), var_values.len());
+
+        let mut nested_goals = vec![];
         for (&orig, response) in iter::zip(original_values, var_values.var_values) {
-            // This can fail due to the occurs check, see
-            // `tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs` for an example
-            // where that can happen.
-            //
-            // FIXME: To deal with #105787 I also expect us to emit nested obligations here at
-            // some point. We can figure out how to deal with this once we actually have
-            // an ICE.
-            let nested_goals = self.eq_and_get_goals(param_env, orig, response)?;
-            assert!(nested_goals.is_empty(), "{nested_goals:?}");
+            nested_goals.extend(self.eq_and_get_goals(param_env, orig, response)?);
         }
 
-        Ok(())
+        Ok(nested_goals)
     }
 
     fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index c492c8c0aea..e47b5ae21b5 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -70,7 +70,7 @@ pub trait InferCtxtEvalExt<'tcx> {
     fn evaluate_root_goal(
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution>;
+    ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>;
 }
 
 impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
@@ -78,9 +78,8 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
     fn evaluate_root_goal(
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution> {
+    ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
         let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
-
         let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
 
         let mut ecx = EvalCtxt {
@@ -152,13 +151,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         &mut self,
         is_normalizes_to_hack: IsNormalizesToHack,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(bool, Certainty), NoSolution> {
+    ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
         let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
         let canonical_response =
             EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
 
         let has_changed = !canonical_response.value.var_values.is_identity();
-        let certainty = self.instantiate_and_apply_query_response(
+        let (certainty, nested_goals) = self.instantiate_and_apply_query_response(
             goal.param_env,
             orig_values,
             canonical_response,
@@ -186,7 +185,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             assert_eq!(certainty, canonical_response.value.certainty);
         }
 
-        Ok((has_changed, certainty))
+        Ok((has_changed, certainty, nested_goals))
     }
 
     fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
@@ -236,9 +235,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
-                ty::PredicateKind::AliasEq(lhs, rhs) => {
-                    self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
-                }
+                ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
+                    .compute_alias_relate_goal(Goal {
+                        param_env,
+                        predicate: (lhs, rhs, direction),
+                    }),
             }
         } else {
             let kind = self.infcx.instantiate_binder_with_placeholders(kind);
@@ -261,13 +262,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 let mut has_changed = Err(Certainty::Yes);
 
                 if let Some(goal) = goals.normalizes_to_hack_goal.take() {
-                    let (_, certainty) = match this.evaluate_goal(
+                    let (_, certainty, nested_goals) = match this.evaluate_goal(
                         IsNormalizesToHack::Yes,
                         goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)),
                     ) {
                         Ok(r) => r,
                         Err(NoSolution) => return Some(Err(NoSolution)),
                     };
+                    new_goals.goals.extend(nested_goals);
 
                     if goal.predicate.projection_ty
                         != this.resolve_vars_if_possible(goal.predicate.projection_ty)
@@ -306,11 +308,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 }
 
                 for nested_goal in goals.goals.drain(..) {
-                    let (changed, certainty) =
+                    let (changed, certainty, nested_goals) =
                         match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) {
                             Ok(result) => result,
                             Err(NoSolution) => return Some(Err(NoSolution)),
                         };
+                    new_goals.goals.extend(nested_goals);
 
                     if changed {
                         has_changed = Ok(());
@@ -470,6 +473,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             })
     }
 
+    #[instrument(level = "debug", skip(self, param_env), ret)]
+    pub(super) fn sub<T: ToTrace<'tcx>>(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        sub: T,
+        sup: T,
+    ) -> Result<(), NoSolution> {
+        self.infcx
+            .at(&ObligationCause::dummy(), param_env)
+            .sub(DefineOpaqueTypes::No, sub, sup)
+            .map(|InferOk { value: (), obligations }| {
+                self.add_goals(obligations.into_iter().map(|o| o.into()));
+            })
+            .map_err(|e| {
+                debug!(?e, "failed to subtype");
+                NoSolution
+            })
+    }
+
     /// Equates two values returning the nested goals without adding them
     /// to the nested goals of the `EvalCtxt`.
     ///
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 38120b9760f..76a2a587911 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -1,6 +1,7 @@
 use std::mem;
 
 use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::Obligation;
 use rustc_infer::traits::{
     query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
     PredicateObligation, SelectionError, TraitEngine,
@@ -61,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
             let mut has_changed = false;
             for obligation in mem::take(&mut self.obligations) {
                 let goal = obligation.clone().into();
-                let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
+                let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) {
                     Ok(result) => result,
                     Err(NoSolution) => {
                         errors.push(FulfillmentError {
@@ -73,7 +74,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                                         MismatchedProjectionTypes { err: TypeError::Mismatch },
                                     )
                                 }
-                                ty::PredicateKind::AliasEq(_, _) => {
+                                ty::PredicateKind::AliasRelate(_, _, _) => {
                                     FulfillmentErrorCode::CodeProjectionError(
                                         MismatchedProjectionTypes { err: TypeError::Mismatch },
                                     )
@@ -125,7 +126,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                         continue;
                     }
                 };
-
+                // Push any nested goals that we get from unifying our canonical response
+                // with our obligation onto the fulfillment context.
+                self.obligations.extend(nested_goals.into_iter().map(|goal| {
+                    Obligation::new(
+                        infcx.tcx,
+                        obligation.cause.clone(),
+                        goal.param_env,
+                        goal.predicate,
+                    )
+                }));
                 has_changed |= changed;
                 match certainty {
                     Certainty::Yes => {}
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 89f4056a58d..6a64dfdedd4 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -13,7 +13,6 @@
 
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
     CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
@@ -110,11 +109,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             // That won't actually reflect in the query response, so it seems moot.
             self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
         } else {
-            let InferOk { value: (), obligations } = self
-                .infcx
-                .at(&ObligationCause::dummy(), goal.param_env)
-                .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?;
-            self.add_goals(obligations.into_iter().map(|pred| pred.into()));
+            self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
             self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         }
     }
@@ -165,55 +160,94 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self), ret)]
-    fn compute_alias_eq_goal(
+    fn compute_alias_relate_goal(
         &mut self,
-        goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>,
+        goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
     ) -> QueryResult<'tcx> {
         let tcx = self.tcx();
+        // We may need to invert the alias relation direction if dealing an alias on the RHS.
+        enum Invert {
+            No,
+            Yes,
+        }
+        let evaluate_normalizes_to =
+            |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| {
+                debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
+                let result = ecx.probe(|ecx| {
+                    let other = match direction {
+                        // This is purely an optimization.
+                        ty::AliasRelationDirection::Equate => other,
+
+                        ty::AliasRelationDirection::Subtype => {
+                            let fresh = ecx.next_term_infer_of_kind(other);
+                            let (sub, sup) = match invert {
+                                Invert::No => (fresh, other),
+                                Invert::Yes => (other, fresh),
+                            };
+                            ecx.sub(goal.param_env, sub, sup)?;
+                            fresh
+                        }
+                    };
+                    ecx.add_goal(goal.with(
+                        tcx,
+                        ty::Binder::dummy(ty::ProjectionPredicate {
+                            projection_ty: alias,
+                            term: other,
+                        }),
+                    ));
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                });
+                debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}");
+                result
+            };
 
-        let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
-            debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
-            let r = ecx.probe(|ecx| {
-                ecx.add_goal(goal.with(
-                    tcx,
-                    ty::Binder::dummy(ty::ProjectionPredicate {
-                        projection_ty: alias,
-                        term: other,
-                    }),
-                ));
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            });
-            debug!("evaluate_normalizes_to(..) -> {:?}", r);
-            r
-        };
+        let (lhs, rhs, direction) = goal.predicate;
 
-        if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() {
+        if lhs.is_infer() || rhs.is_infer() {
             bug!(
-                "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated"
+                "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
             );
         }
 
-        match (
-            goal.predicate.0.to_alias_term_no_opaque(tcx),
-            goal.predicate.1.to_alias_term_no_opaque(tcx),
-        ) {
-            (None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"),
-            (Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1),
-            (None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0),
-            (Some(alias_lhs), Some(alias_rhs)) => {
-                debug!("compute_alias_eq_goal: both sides are aliases");
+        match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) {
+            (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
 
-                let mut candidates = Vec::with_capacity(3);
+            // RHS is not a projection, only way this is true is if LHS normalizes-to RHS
+            (Some(alias_lhs), None) => {
+                evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No)
+            }
 
-                // Evaluate all 3 potential candidates for the alias' being equal
-                candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
-                candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
-                candidates.push(self.probe(|ecx| {
-                    debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
-                    ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                }));
+            // LHS is not a projection, only way this is true is if RHS normalizes-to LHS
+            (None, Some(alias_rhs)) => {
+                evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes)
+            }
 
+            (Some(alias_lhs), Some(alias_rhs)) => {
+                debug!("compute_alias_relate_goal: both sides are aliases");
+
+                let candidates = vec![
+                    // LHS normalizes-to RHS
+                    evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No),
+                    // RHS normalizes-to RHS
+                    evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes),
+                    // Relate via substs
+                    self.probe(|ecx| {
+                        debug!(
+                            "compute_alias_relate_goal: alias defids are equal, equating substs"
+                        );
+
+                        match direction {
+                            ty::AliasRelationDirection::Equate => {
+                                ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
+                            }
+                            ty::AliasRelationDirection::Subtype => {
+                                ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
+                            }
+                        }
+
+                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                    }),
+                ];
                 debug!(?candidates);
 
                 self.try_merge_responses(candidates.into_iter())
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index dbf6775afc2..6b3a59b1ed5 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -832,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 // the `ParamEnv`.
                 ty::PredicateKind::WellFormed(..)
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
index 1174efdbfa8..13607b9079a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
@@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
 }
 
 impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        // FIXME(deferred_projection_equality): We really should get rid of this relation.
+        ty::AliasRelationDirection::Equate
+    }
+
     fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
         // FIXME(deferred_projection_equality)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 41ffaeeac1c..296fd1ed524 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1276,16 +1276,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         "TypeWellFormedFromEnv predicate should only exist in the environment"
                     ),
 
-                    ty::PredicateKind::AliasEq(..) => span_bug!(
+                    ty::PredicateKind::AliasRelate(..) => span_bug!(
                         span,
-                        "AliasEq predicate should never be the predicate cause of a SelectionError"
+                        "AliasRelate predicate should never be the predicate cause of a SelectionError"
                     ),
 
                     ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
-                        self.tcx.sess.struct_span_err(
+                        let mut diag = self.tcx.sess.struct_span_err(
                             span,
                             &format!("the constant `{}` is not of type `{}`", ct, ty),
-                        )
+                        );
+                        self.note_type_err(
+                            &mut diag,
+                            &obligation.cause,
+                            None,
+                            None,
+                            TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())),
+                            false,
+                            false,
+                        );
+                        diag
                     }
                 }
             }
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 af108ab6f30..be0817472ea 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1356,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
+                        let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
+                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
+                        let sugg_msg = &format!(
+                            "consider{} borrowing here",
+                            if is_mut { " mutably" } else { "" }
+                        );
+
+                        // Issue #109436, we need to add parentheses properly for method calls
+                        // for example, `foo.into()` should be `(&foo).into()`
+                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(
+                            self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)),
+                        ) {
+                            if snippet == "." {
+                                err.multipart_suggestion_verbose(
+                                    sugg_msg,
+                                    vec![
+                                        (span.shrink_to_lo(), format!("({}", sugg_prefix)),
+                                        (span.shrink_to_hi(), ")".to_string()),
+                                    ],
+                                    Applicability::MaybeIncorrect,
+                                );
+                                return true;
+                            }
+                        }
+
                         // Issue #104961, we need to add parentheses properly for compond expressions
                         // for example, `x.starts_with("hi".to_string() + "you")`
                         // should be `x.starts_with(&("hi".to_string() + "you"))`
@@ -1372,14 +1397,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             _ => false,
                         };
 
-                        let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
                         let span = if needs_parens { span } else { span.shrink_to_lo() };
-                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
-                        let sugg_msg = &format!(
-                            "consider{} borrowing here",
-                            if is_mut { " mutably" } else { "" }
-                        );
-
                         let suggestions = if !needs_parens {
                             vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
                         } else {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 23754480fcf..07e31e87bfb 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -361,8 +361,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
-                ty::PredicateKind::AliasEq(..) => {
-                    bug!("AliasEq is only used for new solver")
+                ty::PredicateKind::AliasRelate(..) => {
+                    bug!("AliasRelate is only used for new solver")
                 }
             },
             Some(pred) => match pred {
@@ -630,8 +630,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
-                ty::PredicateKind::AliasEq(..) => {
-                    bug!("AliasEq is only used for new solver")
+                ty::PredicateKind::AliasRelate(..) => {
+                    bug!("AliasRelate is only used for new solver")
                 }
                 ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
                     match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 038f8964471..5d2af5ff33c 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -335,7 +335,7 @@ fn predicate_references_self<'tcx>(
             has_self_ty(&ty.into()).then_some(sp)
         }
 
-        ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"),
+        ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"),
 
         ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
@@ -395,7 +395,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
         }
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index f84b2f4428d..edbe2de8105 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -1,9 +1,8 @@
-use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause};
+use rustc_infer::traits::{TraitEngine, TraitEngineExt};
 use rustc_middle::ty;
 
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
-use crate::solve::InferCtxtEvalExt;
 use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
 
 pub trait InferCtxtExt<'tcx> {
@@ -81,27 +80,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
 
         if self.tcx.trait_solver_next() {
             self.probe(|snapshot| {
-                if let Ok((_, certainty)) =
-                    self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate))
-                {
-                    match certainty {
-                        Certainty::Yes => {
-                            if self.opaque_types_added_in_snapshot(snapshot) {
-                                Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
-                            } else if self.region_constraints_added_in_snapshot(snapshot).is_some()
-                            {
-                                Ok(EvaluationResult::EvaluatedToOkModuloRegions)
-                            } else {
-                                Ok(EvaluationResult::EvaluatedToOk)
-                            }
-                        }
-                        Certainty::Maybe(MaybeCause::Ambiguity) => {
-                            Ok(EvaluationResult::EvaluatedToAmbig)
-                        }
-                        Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical),
-                    }
-                } else {
+                let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
+                fulfill_cx.register_predicate_obligation(self, obligation.clone());
+                // True errors
+                // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
+                if !fulfill_cx.select_where_possible(self).is_empty() {
                     Ok(EvaluationResult::EvaluatedToErr)
+                } else if !fulfill_cx.select_all_or_error(self).is_empty() {
+                    Ok(EvaluationResult::EvaluatedToAmbig)
+                } else if self.opaque_types_added_in_snapshot(snapshot) {
+                    Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes)
+                } else if self.region_constraints_added_in_snapshot(snapshot).is_some() {
+                    Ok(EvaluationResult::EvaluatedToOkModuloRegions)
+                } else {
+                    Ok(EvaluationResult::EvaluatedToOk)
                 }
             })
         } else {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index b8758ad9323..4f429f018ed 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -618,6 +618,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
         fulfill_cx.register_predicate_obligations(self.infcx, predicates);
         // True errors
+        // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
         if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
             return Ok(EvaluatedToErr);
         }
@@ -977,8 +978,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
-                ty::PredicateKind::AliasEq(..) => {
-                    bug!("AliasEq is only used for new solver")
+                ty::PredicateKind::AliasRelate(..) => {
+                    bug!("AliasRelate is only used for new solver")
                 }
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index cd665d9471d..11eb968a415 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -3,7 +3,7 @@ use super::OverlapError;
 use crate::traits;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 
 pub use rustc_middle::traits::specialization_graph::*;
@@ -49,12 +49,9 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
-        if let Some(st) = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            TreatParams::AsCandidateKey,
-            TreatProjections::AsCandidateKey,
-        ) {
+        if let Some(st) =
+            fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey)
+        {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
             self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
         } else {
@@ -69,12 +66,9 @@ impl<'tcx> ChildrenExt<'tcx> for Children {
     fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         let vec: &mut Vec<DefId>;
-        if let Some(st) = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            TreatParams::AsCandidateKey,
-            TreatProjections::AsCandidateKey,
-        ) {
+        if let Some(st) =
+            fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey)
+        {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
             vec = self.non_blanket_impls.get_mut(&st).unwrap();
         } else {
@@ -310,12 +304,8 @@ impl<'tcx> GraphExt<'tcx> for Graph {
 
         let mut parent = trait_def_id;
         let mut last_lint = None;
-        let simplified = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            TreatParams::AsCandidateKey,
-            TreatProjections::AsCandidateKey,
-        );
+        let simplified =
+            fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey);
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d498af359c5..ec5bd982a3c 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>(
         ty::PredicateKind::TypeWellFormedFromEnv(..) => {
             bug!("TypeWellFormedFromEnv is only used for Chalk")
         }
-        ty::PredicateKind::AliasEq(..) => {
-            bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`")
+        ty::PredicateKind::AliasRelate(..) => {
+            bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`")
         }
     }
 
@@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                 ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
                     ref t,
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 60e22d1001c..0e9bccba8d4 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -119,7 +119,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 },
                 ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
@@ -215,7 +215,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             // some of these in terms of chalk operations.
             ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::Ambiguous
@@ -652,7 +652,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
             ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
@@ -787,7 +787,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
             ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index ddd4ca1436c..f5bba14d2fb 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -86,7 +86,7 @@ fn compute_implied_outlives_bounds<'tcx>(
             if obligation.predicate.has_non_region_infer() {
                 match obligation.predicate.kind().skip_binder() {
                     ty::PredicateKind::Clause(ty::Clause::Projection(..))
-                    | ty::PredicateKind::AliasEq(..) => {
+                    | ty::PredicateKind::AliasRelate(..) => {
                         ocx.register_obligation(obligation.clone());
                     }
                     _ => {}
@@ -110,7 +110,7 @@ fn compute_implied_outlives_bounds<'tcx>(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
 
                 // We need to search through *all* WellFormed predicates
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index f0597f19225..126a494f34f 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -61,7 +61,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
         ty::PredicateKind::Clause(ty::Clause::Trait(..))
         | ty::PredicateKind::Clause(ty::Clause::Projection(..))
         | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-        | ty::PredicateKind::AliasEq(..)
+        | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 5a991e03dee..8b23fbc7583 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -432,6 +432,17 @@ impl IntTy {
             _ => *self,
         }
     }
+
+    pub fn to_unsigned(self) -> UintTy {
+        match self {
+            IntTy::Isize => UintTy::Usize,
+            IntTy::I8 => UintTy::U8,
+            IntTy::I16 => UintTy::U16,
+            IntTy::I32 => UintTy::U32,
+            IntTy::I64 => UintTy::U64,
+            IntTy::I128 => UintTy::U128,
+        }
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
@@ -479,6 +490,17 @@ impl UintTy {
             _ => *self,
         }
     }
+
+    pub fn to_signed(self) -> IntTy {
+        match self {
+            UintTy::Usize => IntTy::Isize,
+            UintTy::U8 => IntTy::I8,
+            UintTy::U16 => IntTy::I16,
+            UintTy::U32 => IntTy::I32,
+            UintTy::U64 => IntTy::I64,
+            UintTy::U128 => IntTy::I128,
+        }
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 089b6b6418d..1e9cf404f77 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -692,10 +692,10 @@ impl<T> Rc<T> {
     /// it is guaranteed that exactly one of the calls returns the inner value.
     /// This means in particular that the inner value is not dropped.
     ///
-    /// This is equivalent to `Rc::try_unwrap(...).ok()`. (Note that these are not equivalent for
-    /// `Arc`, due to race conditions that do not apply to `Rc`.)
+    /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for
+    /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.)
     #[inline]
-    #[unstable(feature = "rc_into_inner", issue = "106894")]
+    #[stable(feature = "rc_into_inner", since = "CURRENT_RUSTC_VERSION")]
     pub fn into_inner(this: Self) -> Option<T> {
         Rc::try_unwrap(this).ok()
     }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 8a27a7ecdf6..150924851d2 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -662,20 +662,17 @@ impl<T> Arc<T> {
     ///
     /// This will succeed even if there are outstanding weak references.
     ///
-    // FIXME: when `Arc::into_inner` is stabilized, add this paragraph:
-    /*
     /// It is strongly recommended to use [`Arc::into_inner`] instead if you don't
     /// want to keep the `Arc` in the [`Err`] case.
     /// Immediately dropping the [`Err`] payload, like in the expression
     /// `Arc::try_unwrap(this).ok()`, can still cause the strong count to
     /// drop to zero and the inner value of the `Arc` to be dropped:
-    /// For instance if two threads execute this expression in parallel, then
+    /// For instance if two threads each execute this expression in parallel, then
     /// there is a race condition. The threads could first both check whether they
     /// have the last clone of their `Arc` via `Arc::try_unwrap`, and then
     /// both drop their `Arc` in the call to [`ok`][`Result::ok`],
     /// taking the strong count from two down to zero.
     ///
-     */
     /// # Examples
     ///
     /// ```
@@ -719,20 +716,13 @@ impl<T> Arc<T> {
     /// This means in particular that the inner value is not dropped.
     ///
     /// The similar expression `Arc::try_unwrap(this).ok()` does not
-    /// offer such a guarantee. See the last example below.
-    //
-    // FIXME: when `Arc::into_inner` is stabilized, add this to end
-    // of the previous sentence:
-    /*
+    /// offer such a guarantee. See the last example below
     /// and the documentation of [`Arc::try_unwrap`].
-     */
     ///
     /// # Examples
     ///
     /// Minimal example demonstrating the guarantee that `Arc::into_inner` gives.
     /// ```
-    /// #![feature(arc_into_inner)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let x = Arc::new(3);
@@ -756,8 +746,6 @@ impl<T> Arc<T> {
     ///
     /// A more practical example demonstrating the need for `Arc::into_inner`:
     /// ```
-    /// #![feature(arc_into_inner)]
-    ///
     /// use std::sync::Arc;
     ///
     /// // Definition of a simple singly linked list using `Arc`:
@@ -807,13 +795,8 @@ impl<T> Arc<T> {
     /// x_thread.join().unwrap();
     /// y_thread.join().unwrap();
     /// ```
-
-    // FIXME: when `Arc::into_inner` is stabilized, adjust above documentation
-    // and the documentation of `Arc::try_unwrap` according to the `FIXME`s. Also
-    // open an issue on rust-lang/rust-clippy, asking for a lint against
-    // `Arc::try_unwrap(...).ok()`.
     #[inline]
-    #[unstable(feature = "arc_into_inner", issue = "106894")]
+    #[stable(feature = "arc_into_inner", since = "CURRENT_RUSTC_VERSION")]
     pub fn into_inner(this: Self) -> Option<T> {
         // Make sure that the ordinary `Drop` implementation isn’t called as well
         let mut this = mem::ManuallyDrop::new(this);
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 3061f76df04..6690c1a76d5 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -344,6 +344,14 @@ define!(
     fn Variant<T>(place: T, index: u32) -> ()
 );
 define!(
+    "mir_cast_transmute",
+    /// Emits a `CastKind::Transmute` cast.
+    ///
+    /// Needed to test the UB when `sizeof(T) != sizeof(U)`, which can't be
+    /// generated via the normal `mem::transmute`.
+    fn CastTransmute<T, U>(operand: T) -> U
+);
+define!(
     "mir_make_place",
     #[doc(hidden)]
     fn __internal_make_place<T>(place: T) -> *mut T
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index dd0105c0eb4..35da9151b6f 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -29,6 +29,9 @@
 use crate::fmt;
 use crate::panic::{Location, PanicInfo};
 
+#[cfg(feature = "panic_immediate_abort")]
+const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort");
+
 // First we define the two main entry points that all panics go through.
 // In the end both are just convenience wrappers around `panic_impl`.
 
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 7f07e4fddef..1cedd6eedfa 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -370,7 +370,7 @@ pub enum ErrorKind {
 
     // "Unusual" error kinds which do not correspond simply to (sets
     // of) OS error codes, should be added just above this comment.
-    // `Other` and `Uncategorised` should remain at the end:
+    // `Other` and `Uncategorized` should remain at the end:
     //
     /// A custom error that does not fall under any other I/O error kind.
     ///
@@ -882,6 +882,13 @@ impl Error {
 
     /// Returns the corresponding [`ErrorKind`] for this error.
     ///
+    /// This may be a value set by Rust code constructing custom `io::Error`s,
+    /// or if this `io::Error` was sourced from the operating system,
+    /// it will be a value inferred from the system's error encoding.
+    /// See [`last_os_error`] for more details.
+    ///
+    /// [`last_os_error`]: Error::last_os_error
+    ///
     /// # Examples
     ///
     /// ```
@@ -892,7 +899,8 @@ impl Error {
     /// }
     ///
     /// fn main() {
-    ///     // Will print "Uncategorized".
+    ///     // As no error has (visibly) occurred, this may print anything!
+    ///     // It likely prints a placeholder for unidentified (non-)errors.
     ///     print_error(Error::last_os_error());
     ///     // Will print "AddrInUse".
     ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 065045f4420..b8fec6902a0 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -107,8 +107,8 @@ use crate::sys::locks as sys;
 /// *guard += 1;
 /// ```
 ///
-/// It is sometimes necessary to manually drop the mutex guard to unlock it
-/// sooner than the end of the enclosing scope.
+/// To unlock a mutex guard sooner than the end of the enclosing scope,
+/// either create an inner scope or drop the guard manually.
 ///
 /// ```
 /// use std::sync::{Arc, Mutex};
@@ -125,11 +125,18 @@ use crate::sys::locks as sys;
 ///     let res_mutex_clone = Arc::clone(&res_mutex);
 ///
 ///     threads.push(thread::spawn(move || {
-///         let mut data = data_mutex_clone.lock().unwrap();
-///         // This is the result of some important and long-ish work.
-///         let result = data.iter().fold(0, |acc, x| acc + x * 2);
-///         data.push(result);
-///         drop(data);
+///         // Here we use a block to limit the lifetime of the lock guard.
+///         let result = {
+///             let mut data = data_mutex_clone.lock().unwrap();
+///             // This is the result of some important and long-ish work.
+///             let result = data.iter().fold(0, |acc, x| acc + x * 2);
+///             data.push(result);
+///             result
+///             // The mutex guard gets dropped here, together with any other values
+///             // created in the critical section.
+///         };
+///         // The guard created here is a temporary dropped at the end of the statement, i.e.
+///         // the lock would not remain being held even if the thread did some additional work.
 ///         *res_mutex_clone.lock().unwrap() += result;
 ///     }));
 /// });
@@ -146,6 +153,8 @@ use crate::sys::locks as sys;
 /// // It's even more important here than in the threads because we `.join` the
 /// // threads after that. If we had not dropped the mutex guard, a thread could
 /// // be waiting forever for it, causing a deadlock.
+/// // As in the threads, a block could have been used instead of calling the
+/// // `drop` function.
 /// drop(data);
 /// // Here the mutex guard is not assigned to a variable and so, even if the
 /// // scope does not end after this line, the mutex is still released: there is
@@ -160,6 +169,7 @@ use crate::sys::locks as sys;
 ///
 /// assert_eq!(*res_mutex.lock().unwrap(), 800);
 /// ```
+///
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")]
 pub struct Mutex<T: ?Sized> {
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index c966f217757..cf0b271761f 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -202,7 +202,7 @@ impl OpenOptions {
             create: false,
             create_new: false,
             // system-specific
-            mode: 0x777,
+            mode: 0o777,
         }
     }
 
diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
index d9e58386256..b5abf6564a6 100644
--- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
@@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   lib32z1-dev \
   xz-utils \
+  mingw-w64 \
   && rm -rf /var/lib/apt/lists/*
 
 
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile
index b99a0886b4d..21dcf29b4a9 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile
@@ -22,6 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   xz-utils \
   nodejs \
+  mingw-w64 \
   && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
index dc8a4aac768..cfb638e8b07 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
@@ -23,6 +23,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   xz-utils \
   nodejs \
+  mingw-w64 \
   && rm -rf /var/lib/apt/lists/*
 
 # Install powershell (universal package) so we can test x.ps1 on Linux
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
index 5219247cc6f..fb5037e3b97 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
@@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   xz-utils \
   nodejs \
+  mingw-w64 \
   && rm -rf /var/lib/apt/lists/*
 
 # Install powershell (universal package) so we can test x.ps1 on Linux
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
index 5b9581f72a6..fbec368c9ee 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
@@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config \
   xz-utils \
+  mingw-w64 \
   && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md
index 28a004a9253..2957916d56c 100644
--- a/src/doc/rustdoc/src/how-to-read-rustdoc.md
+++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md
@@ -80,13 +80,20 @@ functions, and "In Return Types" shows matches in the return types of functions.
 Both are very useful when looking for a function whose name you can't quite
 bring to mind when you know the type you have or want.
 
-When typing in the search bar, you can prefix your search term with a type
-followed by a colon (such as `mod:`) to restrict the results to just that
-kind of item. (The available items are listed in the help popup.)
-
-Searching for `println!` will search for a macro named `println`, just like
+Names in the search interface can be prefixed with an item type followed by a
+colon (such as `mod:`) to restrict the results to just that kind of item. Also,
+searching for `println!` will search for a macro named `println`, just like
 searching for `macro:println` does.
 
+Function signature searches can query generics, wrapped in angle brackets, and
+traits are normalized like types in the search engine. For example, a function
+with the signature `fn my_function<I: Iterator<Item=u32>>(input: I) -> usize`
+can be matched with the following queries:
+
+* `Iterator<u32> -> usize`
+* `trait:Iterator<primitive:u32> -> primitive:usize`
+* `Iterator -> usize`
+
 ### Changing displayed theme
 
 You can change the displayed theme by opening the settings menu (the gear
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2e1f456f50e..c00fa5994bf 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -324,7 +324,7 @@ pub(crate) fn clean_predicate<'tcx>(
         ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
         ty::PredicateKind::Subtype(..)
-        | ty::PredicateKind::AliasEq(..)
+        | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 7dbb3f76a0a..a21a91a0ce8 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -482,10 +482,12 @@ impl Item {
     pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
         use crate::html::format::{href, link_tooltip};
 
-        cx.cache()
+        let Some(links) = cx.cache()
             .intra_doc_links
-            .get(&self.item_id)
-            .map_or(&[][..], |v| v.as_slice())
+            .get(&self.item_id) else {
+                return vec![]
+            };
+        links
             .iter()
             .filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| {
                 debug!(?id);
@@ -513,10 +515,12 @@ impl Item {
     /// the link text, but does need to know which `[]`-bracketed names
     /// are actually links.
     pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
-        cache
+        let Some(links) = cache
             .intra_doc_links
-            .get(&self.item_id)
-            .map_or(&[][..], |v| v.as_slice())
+            .get(&self.item_id) else {
+                return vec![];
+            };
+        links
             .iter()
             .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
                 original_text: s.clone(),
@@ -1014,7 +1018,7 @@ pub(crate) fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
 /// A link that has not yet been rendered.
 ///
 /// This link will be turned into a rendered link by [`Item::links`].
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub(crate) struct ItemLink {
     /// The original link written in the markdown
     pub(crate) link: Box<str>,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 0295de8437e..c0329182032 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,6 +1,6 @@
 use std::mem;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
@@ -118,7 +118,7 @@ pub(crate) struct Cache {
     /// All intra-doc links resolved so far.
     ///
     /// Links are indexed by the DefId of the item they document.
-    pub(crate) intra_doc_links: FxHashMap<ItemId, Vec<clean::ItemLink>>,
+    pub(crate) intra_doc_links: FxHashMap<ItemId, FxIndexSet<clean::ItemLink>>,
     /// Cfg that have been hidden via #![doc(cfg_hide(...))]
     pub(crate) hidden_cfg: FxHashSet<clean::cfg::Cfg>,
 }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 36ff20e299e..840ed8e1080 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -354,12 +354,15 @@ function initSearch(rawSearchIndex) {
         if (isInGenerics) {
             parserState.genericsElems += 1;
         }
+        const typeFilter = parserState.typeFilter;
+        parserState.typeFilter = null;
         return {
             name: name,
             fullPath: pathSegments,
             pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
             pathLast: pathSegments[pathSegments.length - 1],
             generics: generics,
+            typeFilter,
         };
     }
 
@@ -495,6 +498,11 @@ function initSearch(rawSearchIndex) {
      */
     function getItemsBefore(query, parserState, elems, endChar) {
         let foundStopChar = true;
+        let start = parserState.pos;
+
+        // If this is a generic, keep the outer item's type filter around.
+        const oldTypeFilter = parserState.typeFilter;
+        parserState.typeFilter = null;
 
         while (parserState.pos < parserState.length) {
             const c = parserState.userQuery[parserState.pos];
@@ -506,7 +514,25 @@ function initSearch(rawSearchIndex) {
                 continue;
             } else if (c === ":" && isPathStart(parserState)) {
                 throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
-            } else if (c === ":" || isEndCharacter(c)) {
+            }  else if (c === ":") {
+                if (parserState.typeFilter !== null) {
+                    throw ["Unexpected ", ":"];
+                }
+                if (elems.length === 0) {
+                    throw ["Expected type filter before ", ":"];
+                } else if (query.literalSearch) {
+                    throw ["You cannot use quotes on type filter"];
+                }
+                // The type filter doesn't count as an element since it's a modifier.
+                const typeFilterElem = elems.pop();
+                checkExtraTypeFilterCharacters(start, parserState);
+                parserState.typeFilter = typeFilterElem.name;
+                parserState.pos += 1;
+                parserState.totalElems -= 1;
+                query.literalSearch = false;
+                foundStopChar = true;
+                continue;
+            } else if (isEndCharacter(c)) {
                 let extra = "";
                 if (endChar === ">") {
                     extra = "<";
@@ -540,15 +566,10 @@ function initSearch(rawSearchIndex) {
                 ];
             }
             const posBefore = parserState.pos;
+            start = parserState.pos;
             getNextElem(query, parserState, elems, endChar === ">");
-            if (endChar !== "") {
-                if (parserState.pos >= parserState.length) {
-                    throw ["Unclosed ", "<"];
-                }
-                const c2 = parserState.userQuery[parserState.pos];
-                if (!isSeparatorCharacter(c2) && c2 !== endChar) {
-                    throw ["Expected ", endChar, ", found ", c2];
-                }
+            if (endChar !== "" && parserState.pos >= parserState.length) {
+                throw ["Unclosed ", "<"];
             }
             // This case can be encountered if `getNextElem` encountered a "stop character" right
             // from the start. For example if you have `,,` or `<>`. In this case, we simply move up
@@ -564,6 +585,8 @@ function initSearch(rawSearchIndex) {
         // We are either at the end of the string or on the `endChar` character, let's move forward
         // in any case.
         parserState.pos += 1;
+
+        parserState.typeFilter = oldTypeFilter;
     }
 
     /**
@@ -572,10 +595,10 @@ function initSearch(rawSearchIndex) {
      *
      * @param {ParserState} parserState
      */
-    function checkExtraTypeFilterCharacters(parserState) {
+    function checkExtraTypeFilterCharacters(start, parserState) {
         const query = parserState.userQuery;
 
-        for (let pos = 0; pos < parserState.pos; ++pos) {
+        for (let pos = start; pos < parserState.pos; ++pos) {
             if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
                 throw ["Unexpected ", query[pos], " in type filter"];
             }
@@ -591,6 +614,7 @@ function initSearch(rawSearchIndex) {
      */
     function parseInput(query, parserState) {
         let foundStopChar = true;
+        let start = parserState.pos;
 
         while (parserState.pos < parserState.length) {
             const c = parserState.userQuery[parserState.pos];
@@ -612,16 +636,15 @@ function initSearch(rawSearchIndex) {
                 }
                 if (query.elems.length === 0) {
                     throw ["Expected type filter before ", ":"];
-                } else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
-                    throw ["Unexpected ", ":"];
                 } else if (query.literalSearch) {
                     throw ["You cannot use quotes on type filter"];
                 }
-                checkExtraTypeFilterCharacters(parserState);
                 // The type filter doesn't count as an element since it's a modifier.
-                parserState.typeFilter = query.elems.pop().name;
+                const typeFilterElem = query.elems.pop();
+                checkExtraTypeFilterCharacters(start, parserState);
+                parserState.typeFilter = typeFilterElem.name;
                 parserState.pos += 1;
-                parserState.totalElems = 0;
+                parserState.totalElems -= 1;
                 query.literalSearch = false;
                 foundStopChar = true;
                 continue;
@@ -653,6 +676,7 @@ function initSearch(rawSearchIndex) {
                 ];
             }
             const before = query.elems.length;
+            start = parserState.pos;
             getNextElem(query, parserState, query.elems, false);
             if (query.elems.length === before) {
                 // Nothing was added, weird... Let's increase the position to not remain stuck.
@@ -660,6 +684,9 @@ function initSearch(rawSearchIndex) {
             }
             foundStopChar = false;
         }
+        if (parserState.typeFilter !== null) {
+            throw ["Unexpected ", ":", " (expected path after type filter)"];
+        }
         while (parserState.pos < parserState.length) {
             if (isReturnArrow(parserState)) {
                 parserState.pos += 2;
@@ -687,7 +714,6 @@ function initSearch(rawSearchIndex) {
         return {
             original: userQuery,
             userQuery: userQuery.toLowerCase(),
-            typeFilter: NO_TYPE_FILTER,
             elems: [],
             returned: [],
             // Total number of "top" elements (does not include generics).
@@ -738,8 +764,8 @@ function initSearch(rawSearchIndex) {
      *
      * ident = *(ALPHA / DIGIT / "_")
      * path = ident *(DOUBLE-COLON ident) [!]
-     * arg = path [generics]
-     * arg-without-generic = path
+     * arg = [type-filter *WS COLON *WS] path [generics]
+     * arg-without-generic = [type-filter *WS COLON *WS] path
      * type-sep = COMMA/WS *(COMMA/WS)
      * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
      * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
@@ -749,7 +775,7 @@ function initSearch(rawSearchIndex) {
      * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
      *
      * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
-     * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
+     * type-search = [ nonempty-arg-list ] [ return-args ]
      *
      * query = *WS (exact-search / type-search) *WS
      *
@@ -798,6 +824,20 @@ function initSearch(rawSearchIndex) {
      * @return {ParsedQuery}    - The parsed query
      */
     function parseQuery(userQuery) {
+        function convertTypeFilterOnElem(elem) {
+            if (elem.typeFilter !== null) {
+                let typeFilter = elem.typeFilter;
+                if (typeFilter === "const") {
+                    typeFilter = "constant";
+                }
+                elem.typeFilter = itemTypeFromName(typeFilter);
+            } else {
+                elem.typeFilter = NO_TYPE_FILTER;
+            }
+            for (const elem2 of elem.generics) {
+                convertTypeFilterOnElem(elem2);
+            }
+        }
         userQuery = userQuery.trim();
         const parserState = {
             length: userQuery.length,
@@ -812,17 +852,15 @@ function initSearch(rawSearchIndex) {
 
         try {
             parseInput(query, parserState);
-            if (parserState.typeFilter !== null) {
-                let typeFilter = parserState.typeFilter;
-                if (typeFilter === "const") {
-                    typeFilter = "constant";
-                }
-                query.typeFilter = itemTypeFromName(typeFilter);
+            for (const elem of query.elems) {
+                convertTypeFilterOnElem(elem);
+            }
+            for (const elem of query.returned) {
+                convertTypeFilterOnElem(elem);
             }
         } catch (err) {
             query = newParsedQuery(userQuery);
             query.error = err;
-            query.typeFilter = -1;
             return query;
         }
 
@@ -1057,12 +1095,10 @@ function initSearch(rawSearchIndex) {
             }
             // The names match, but we need to be sure that all generics kinda
             // match as well.
-            let elem_name;
             if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) {
                 const elems = Object.create(null);
                 for (const entry of row.generics) {
-                    elem_name = entry.name;
-                    if (elem_name === "") {
+                    if (entry.name === "") {
                         // Pure generic, needs to check into it.
                         if (checkGenerics(entry, elem, maxEditDistance + 1, maxEditDistance)
                             !== 0) {
@@ -1070,19 +1106,19 @@ function initSearch(rawSearchIndex) {
                         }
                         continue;
                     }
-                    if (elems[elem_name] === undefined) {
-                        elems[elem_name] = 0;
+                    if (elems[entry.name] === undefined) {
+                        elems[entry.name] = [];
                     }
-                    elems[elem_name] += 1;
+                    elems[entry.name].push(entry.ty);
                 }
                 // We need to find the type that matches the most to remove it in order
                 // to move forward.
-                for (const generic of elem.generics) {
+                const handleGeneric = generic => {
                     let match = null;
                     if (elems[generic.name]) {
                         match = generic.name;
                     } else {
-                        for (elem_name in elems) {
+                        for (const elem_name in elems) {
                             if (!hasOwnPropertyRustdoc(elems, elem_name)) {
                                 continue;
                             }
@@ -1093,12 +1129,32 @@ function initSearch(rawSearchIndex) {
                         }
                     }
                     if (match === null) {
-                        return maxEditDistance + 1;
+                        return false;
                     }
-                    elems[match] -= 1;
-                    if (elems[match] === 0) {
+                    const matchIdx = elems[match].findIndex(tmp_elem =>
+                        typePassesFilter(generic.typeFilter, tmp_elem));
+                    if (matchIdx === -1) {
+                        return false;
+                    }
+                    elems[match].splice(matchIdx, 1);
+                    if (elems[match].length === 0) {
                         delete elems[match];
                     }
+                    return true;
+                };
+                // To do the right thing with type filters, we first process generics
+                // that have them, removing matching ones from the "bag," then do the
+                // ones with no type filter, which can match any entry regardless of its
+                // own type.
+                for (const generic of elem.generics) {
+                    if (generic.typeFilter !== -1 && !handleGeneric(generic)) {
+                        return maxEditDistance + 1;
+                    }
+                }
+                for (const generic of elem.generics) {
+                    if (generic.typeFilter === -1 && !handleGeneric(generic)) {
+                        return maxEditDistance + 1;
+                    }
                 }
                 return 0;
             }
@@ -1145,14 +1201,20 @@ function initSearch(rawSearchIndex) {
                 return maxEditDistance + 1;
             }
 
-            let dist = editDistance(row.name, elem.name, maxEditDistance);
+            let dist;
+            if (typePassesFilter(elem.typeFilter, row.ty)) {
+                dist = editDistance(row.name, elem.name, maxEditDistance);
+            } else {
+                dist = maxEditDistance + 1;
+            }
             if (literalSearch) {
                 if (dist !== 0) {
                     // The name didn't match, let's try to check if the generics do.
                     if (elem.generics.length === 0) {
                         const checkGeneric = row.generics.length > 0;
                         if (checkGeneric && row.generics
-                            .findIndex(tmp_elem => tmp_elem.name === elem.name) !== -1) {
+                            .findIndex(tmp_elem => tmp_elem.name === elem.name &&
+                                typePassesFilter(elem.typeFilter, tmp_elem.ty)) !== -1) {
                             return 0;
                         }
                     }
@@ -1201,22 +1263,21 @@ function initSearch(rawSearchIndex) {
          *
          * @param {Row} row
          * @param {QueryElement} elem    - The element from the parsed query.
-         * @param {integer} typeFilter
+         * @param {integer} maxEditDistance
          * @param {Array<integer>} skipPositions - Do not return one of these positions.
          *
          * @return {dist: integer, position: integer} - Returns an edit distance to the best match.
          *                                              If there is no match, returns
          *                                              `maxEditDistance + 1` and position: -1.
          */
-        function findArg(row, elem, typeFilter, maxEditDistance, skipPositions) {
+        function findArg(row, elem, maxEditDistance, skipPositions) {
             let dist = maxEditDistance + 1;
             let position = -1;
 
             if (row && row.type && row.type.inputs && row.type.inputs.length > 0) {
                 let i = 0;
                 for (const input of row.type.inputs) {
-                    if (!typePassesFilter(typeFilter, input.ty) ||
-                        skipPositions.indexOf(i) !== -1) {
+                    if (skipPositions.indexOf(i) !== -1) {
                         i += 1;
                         continue;
                     }
@@ -1245,14 +1306,14 @@ function initSearch(rawSearchIndex) {
          *
          * @param {Row} row
          * @param {QueryElement} elem   - The element from the parsed query.
-         * @param {integer} typeFilter
+         * @param {integer} maxEditDistance
          * @param {Array<integer>} skipPositions - Do not return one of these positions.
          *
          * @return {dist: integer, position: integer} - Returns an edit distance to the best match.
          *                                              If there is no match, returns
          *                                              `maxEditDistance + 1` and position: -1.
          */
-        function checkReturned(row, elem, typeFilter, maxEditDistance, skipPositions) {
+        function checkReturned(row, elem, maxEditDistance, skipPositions) {
             let dist = maxEditDistance + 1;
             let position = -1;
 
@@ -1260,8 +1321,7 @@ function initSearch(rawSearchIndex) {
                 const ret = row.type.output;
                 let i = 0;
                 for (const ret_ty of ret) {
-                    if (!typePassesFilter(typeFilter, ret_ty.ty) ||
-                        skipPositions.indexOf(i) !== -1) {
+                    if (skipPositions.indexOf(i) !== -1) {
                         i += 1;
                         continue;
                     }
@@ -1483,15 +1543,15 @@ function initSearch(rawSearchIndex) {
             const fullId = row.id;
             const searchWord = searchWords[pos];
 
-            const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance, []);
-            const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance, []);
+            const in_args = findArg(row, elem, maxEditDistance, []);
+            const returned = checkReturned(row, elem, maxEditDistance, []);
 
             // path_dist is 0 because no parent path information is currently stored
             // in the search index
             addIntoResults(results_in_args, fullId, pos, -1, in_args.dist, 0, maxEditDistance);
             addIntoResults(results_returned, fullId, pos, -1, returned.dist, 0, maxEditDistance);
 
-            if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
+            if (!typePassesFilter(elem.typeFilter, row.ty)) {
                 return;
             }
 
@@ -1568,7 +1628,6 @@ function initSearch(rawSearchIndex) {
                     const { dist, position } = callback(
                         row,
                         elem,
-                        NO_TYPE_FILTER,
                         maxEditDistance,
                         skipPositions
                     );
@@ -1632,7 +1691,6 @@ function initSearch(rawSearchIndex) {
                         in_returned = checkReturned(
                             row,
                             elem,
-                            parsedQuery.typeFilter,
                             maxEditDistance,
                             []
                         );
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 0da56e70ed5..32a523f3123 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -969,7 +969,7 @@ impl LinkCollector<'_, '_> {
             for md_link in preprocessed_markdown_links(&doc) {
                 let link = self.resolve_link(item, item_id, module_id, &doc, &md_link);
                 if let Some(link) = link {
-                    self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link);
+                    self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link);
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 24403e8b6f3..9f6adf3e3fa 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"),
+                ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
@@ -176,6 +176,9 @@ fn check_rvalue<'tcx>(
             // FIXME(dyn-star)
             unimplemented!()
         },
+        Rvalue::Cast(CastKind::Transmute, _, _) => {
+            Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into()))
+        },
         // binops are fine on integers
         Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
             check_operand(tcx, lhs, span, body)?;
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 22a0b1d13be..5bc9d9afcb9 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -964,6 +964,19 @@ pub fn make_test_description<R: Read>(
         .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
         .exists();
 
+    fn is_on_path(file: &'static str) -> impl Fn() -> bool {
+        move || env::split_paths(&env::var_os("PATH").unwrap()).any(|dir| dir.join(file).is_file())
+    }
+
+    // On Windows, dlltool.exe is used for all architectures.
+    #[cfg(windows)]
+    let (has_i686_dlltool, has_x86_64_dlltool) =
+        (is_on_path("dlltool.exe"), is_on_path("dlltool.exe"));
+    // For non-Windows, there are architecture specific dlltool binaries.
+    #[cfg(not(windows))]
+    let (has_i686_dlltool, has_x86_64_dlltool) =
+        (is_on_path("i686-w64-mingw32-dlltool"), is_on_path("x86_64-w64-mingw32-dlltool"));
+
     iter_header(path, src, &mut |revision, ln| {
         if revision.is_some() && revision != cfg {
             return;
@@ -1031,6 +1044,8 @@ pub fn make_test_description<R: Read>(
         reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln));
         reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln));
         reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"));
+        reason!(config.parse_name_directive(ln, "needs-i686-dlltool") && !has_i686_dlltool());
+        reason!(config.parse_name_directive(ln, "needs-x86_64-dlltool") && !has_x86_64_dlltool());
         should_fail |= config.parse_name_directive(ln, "should-fail");
     });
 
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 3842a649c6f..034c6aa0708 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -45,6 +45,36 @@ impl Lint {
     fn check_style(&self) -> Result<(), Box<dyn Error>> {
         for &expected in &["### Example", "### Explanation", "{{produces}}"] {
             if expected == "{{produces}}" && self.is_ignored() {
+                if self.doc_contains("{{produces}}") {
+                    return Err(format!(
+                        "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\
+                        \n\
+                        The documentation generator cannot generate the example output when the \
+                        example is ignored.\n\
+                        Manually include the sample output below the example. For example:\n\
+                        \n\
+                        /// ```rust,ignore (needs command line option)\n\
+                        /// #[cfg(widnows)]\n\
+                        /// fn foo() {{}}\n\
+                        /// ```\n\
+                        ///\n\
+                        /// This will produce:\n\
+                        /// \n\
+                        /// ```text\n\
+                        /// warning: unknown condition name used\n\
+                        ///  --> lint_example.rs:1:7\n\
+                        ///   |\n\
+                        /// 1 | #[cfg(widnows)]\n\
+                        ///   |       ^^^^^^^\n\
+                        ///   |\n\
+                        ///   = note: `#[warn(unexpected_cfgs)]` on by default\n\
+                        /// ```\n\
+                        \n\
+                        Replacing the output with the text of the example you \
+                        compiled manually yourself.\n\
+                        "
+                    ).into());
+                }
                 continue;
             }
             if !self.doc_contains(expected) {
@@ -317,10 +347,10 @@ impl<'a> LintExtractor<'a> {
                             ..,
                             &format!(
                                 "This will produce:\n\
-                            \n\
-                            ```text\n\
-                            {}\
-                            ```",
+                                \n\
+                                ```text\n\
+                                {}\
+                                ```",
                                 output
                             ),
                         );
@@ -392,37 +422,36 @@ impl<'a> LintExtractor<'a> {
             .filter(|line| line.starts_with('{'))
             .map(serde_json::from_str)
             .collect::<Result<Vec<serde_json::Value>, _>>()?;
-        match msgs
+        // First try to find the messages with the `code` field set to our lint.
+        let matches: Vec<_> = msgs
             .iter()
-            .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
-        {
-            Some(msg) => {
-                let rendered = msg["rendered"].as_str().expect("rendered field should exist");
-                Ok(rendered.to_string())
-            }
-            None => {
-                match msgs.iter().find(
-                    |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
-                ) {
-                    Some(msg) => {
-                        let rendered = msg["rendered"].as_str().expect("rendered field should exist");
-                        Ok(rendered.to_string())
-                    }
-                    None => {
-                        let rendered: Vec<&str> =
-                            msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
-                        let non_json: Vec<&str> =
-                            stderr.lines().filter(|line| !line.starts_with('{')).collect();
-                        Err(format!(
-                            "did not find lint `{}` in output of example, got:\n{}\n{}",
-                            name,
-                            non_json.join("\n"),
-                            rendered.join("\n")
-                        )
-                        .into())
-                    }
-                }
+            .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
+            .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
+            .collect();
+        if matches.is_empty() {
+            // Some lints override their code to something else (E0566).
+            // Try to find something that looks like it could be our lint.
+            let matches: Vec<_> = msgs.iter().filter(|msg|
+                matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)))
+                .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
+                .collect();
+            if matches.is_empty() {
+                let rendered: Vec<&str> =
+                    msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+                let non_json: Vec<&str> =
+                    stderr.lines().filter(|line| !line.starts_with('{')).collect();
+                Err(format!(
+                    "did not find lint `{}` in output of example, got:\n{}\n{}",
+                    name,
+                    non_json.join("\n"),
+                    rendered.join("\n")
+                )
+                .into())
+            } else {
+                Ok(matches.join("\n"))
             }
+        } else {
+            Ok(matches.join("\n"))
         }
     }
 
diff --git a/src/tools/miri/tests/fail/never_transmute_humans.rs b/src/tools/miri/tests/fail/never_transmute_humans.rs
index de723433dc2..cba3cc0ccf1 100644
--- a/src/tools/miri/tests/fail/never_transmute_humans.rs
+++ b/src/tools/miri/tests/fail/never_transmute_humans.rs
@@ -7,6 +7,6 @@ struct Human;
 
 fn main() {
     let _x: ! = unsafe {
-        std::mem::transmute::<Human, !>(Human) //~ ERROR: transmuting to uninhabited
+        std::mem::transmute::<Human, !>(Human) //~ ERROR: entering unreachable code
     };
 }
diff --git a/src/tools/miri/tests/fail/never_transmute_humans.stderr b/src/tools/miri/tests/fail/never_transmute_humans.stderr
index e8df4739f9b..a51ca7fe7e7 100644
--- a/src/tools/miri/tests/fail/never_transmute_humans.stderr
+++ b/src/tools/miri/tests/fail/never_transmute_humans.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: transmuting to uninhabited type
+error: Undefined Behavior: entering unreachable code
   --> $DIR/never_transmute_humans.rs:LL:CC
    |
 LL |         std::mem::transmute::<Human, !>(Human)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/never_transmute_void.rs b/src/tools/miri/tests/fail/never_transmute_void.rs
index 19473e9ac21..ad67b444616 100644
--- a/src/tools/miri/tests/fail/never_transmute_void.rs
+++ b/src/tools/miri/tests/fail/never_transmute_void.rs
@@ -10,11 +10,13 @@ mod m {
     pub struct Void(VoidI);
 
     pub fn f(v: Void) -> ! {
-        match v.0 {} //~ ERROR: entering unreachable code
+        match v.0 {}
+        //~^ ERROR: entering unreachable code
     }
 }
 
 fn main() {
     let v = unsafe { std::mem::transmute::<(), m::Void>(()) };
-    m::f(v); //~ NOTE: inside `main`
+    m::f(v);
+    //~^ NOTE: inside `main`
 }
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 8d46a8ce7f1..6b9a9b66a7d 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -79,11 +79,18 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position)
             "foundElems",
             "original",
             "returned",
-            "typeFilter",
             "userQuery",
             "error",
         ];
-    } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
+    } else if (fullPath.endsWith("elems") || fullPath.endsWith("returned")) {
+        fieldsToCheck = [
+            "name",
+            "fullPath",
+            "pathWithoutLast",
+            "pathLast",
+            "generics",
+        ];
+    } else if (fullPath.endsWith("generics")) {
         fieldsToCheck = [
             "name",
             "fullPath",
diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs
index 620a3da9463..148d11ee4d6 100644
--- a/tests/assembly/is_aligned.rs
+++ b/tests/assembly/is_aligned.rs
@@ -1,6 +1,7 @@
 // assembly-output: emit-asm
 // min-llvm-version: 15.0
 // only-x86_64
+// ignore-sgx
 // revisions: opt-speed opt-size
 // [opt-speed] compile-flags: -Copt-level=1
 // [opt-size] compile-flags: -Copt-level=s
diff --git a/tests/assembly/strict_provenance.rs b/tests/assembly/strict_provenance.rs
index 01f1957d5f6..24a7c6b5bf1 100644
--- a/tests/assembly/strict_provenance.rs
+++ b/tests/assembly/strict_provenance.rs
@@ -1,6 +1,7 @@
 // assembly-output: emit-asm
 // compile-flags: -Copt-level=1
 // only-x86_64
+// ignore-sgx
 // min-llvm-version: 15.0
 #![crate_type = "rlib"]
 
diff --git a/tests/assembly/x86_64-floating-point-clamp.rs b/tests/assembly/x86_64-floating-point-clamp.rs
index 0f3b465d08d..0bc6baad479 100644
--- a/tests/assembly/x86_64-floating-point-clamp.rs
+++ b/tests/assembly/x86_64-floating-point-clamp.rs
@@ -4,6 +4,7 @@
 // assembly-output: emit-asm
 // compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
 // only-x86_64
+// ignore-sgx
 
 // CHECK-LABEL: clamp_demo:
 #[no_mangle]
diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs
index 79d82cf70d3..7eb3c6948ac 100644
--- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs
+++ b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs
@@ -11,7 +11,7 @@ pub extern fn plus_one(r: &mut u64) {
 
 // CHECK: plus_one
 // CHECK: lfence
-// CHECK-NEXT: addq
+// CHECK-NEXT: incq
 // CHECK: popq [[REGISTER:%[a-z]+]]
 // CHECK-NEXT: lfence
 // CHECK-NEXT: jmpq *[[REGISTER]]
diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs
index c316379d5b1..4745ebc4fcd 100644
--- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs
+++ b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs
@@ -10,9 +10,7 @@ use std::arch::asm;
 pub extern "C" fn get(ptr: *const u64) -> u64 {
     let value: u64;
     unsafe {
-        asm!(".start_inline_asm:",
-            "mov {}, [{}]",
-            ".end_inline_asm:",
+        asm!("mov {}, [{}]",
             out(reg) value,
             in(reg) ptr);
     }
@@ -20,24 +18,17 @@ pub extern "C" fn get(ptr: *const u64) -> u64 {
 }
 
 // CHECK: get
-// CHECK: .start_inline_asm
-// CHECK-NEXT: movq
+// CHECK: movq
 // CHECK-NEXT: lfence
-// CHECK-NEXT: .end_inline_asm
 
 #[no_mangle]
 pub extern "C" fn myret() {
     unsafe {
-        asm!(
-            ".start_myret_inline_asm:",
-            "ret",
-            ".end_myret_inline_asm:",
-        );
+        asm!("ret");
     }
 }
 
 // CHECK: myret
-// CHECK: .start_myret_inline_asm
-// CHECK-NEXT: shlq $0, (%rsp)
+// CHECK: shlq $0, (%rsp)
 // CHECK-NEXT: lfence
 // CHECK-NEXT: retq
diff --git a/tests/assembly/x86_64-no-jump-tables.rs b/tests/assembly/x86_64-no-jump-tables.rs
index 007c3591a4a..edf4adaad41 100644
--- a/tests/assembly/x86_64-no-jump-tables.rs
+++ b/tests/assembly/x86_64-no-jump-tables.rs
@@ -6,6 +6,7 @@
 // compile-flags: -O
 // [set] compile-flags: -Zno-jump-tables
 // only-x86_64
+// ignore-sgx
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs
new file mode 100644
index 00000000000..cefcf9ed9ca
--- /dev/null
+++ b/tests/codegen/intrinsics/transmute.rs
@@ -0,0 +1,196 @@
+// compile-flags: -O -C no-prepopulate-passes
+// only-64bit (so I don't need to worry about usize)
+// min-llvm-version: 15.0 # this test assumes `ptr`s
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+#![feature(custom_mir)]
+#![feature(inline_const)]
+
+use std::mem::transmute;
+
+// Some of the cases here are statically rejected by `mem::transmute`, so
+// we need to generate custom MIR for those cases to get to codegen.
+use std::intrinsics::mir::*;
+
+enum Never {}
+
+#[repr(align(2))]
+pub struct BigNever(Never, u16, Never);
+
+#[repr(align(8))]
+pub struct Scalar64(i64);
+
+#[repr(C, align(4))]
+pub struct Aggregate64(u16, u8, i8, f32);
+
+// CHECK-LABEL: @check_bigger_size(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "initial")]
+pub unsafe fn check_bigger_size(x: u16) -> u32 {
+    // CHECK: call void @llvm.trap
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_smaller_size(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "initial")]
+pub unsafe fn check_smaller_size(x: u32) -> u16 {
+    // CHECK: call void @llvm.trap
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_to_uninhabited(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "initial")]
+pub unsafe fn check_to_uninhabited(x: u16) -> BigNever {
+    // CHECK: call void @llvm.trap
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_from_uninhabited(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "initial")]
+pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
+    // CHECK: call void @llvm.trap
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_to_newtype(
+#[no_mangle]
+pub unsafe fn check_to_newtype(x: u64) -> Scalar64 {
+    // CHECK: %0 = alloca i64
+    // CHECK: store i64 %x, ptr %0
+    // CHECK: %1 = load i64, ptr %0
+    // CHECK: ret i64 %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_newtype(
+#[no_mangle]
+pub unsafe fn check_from_newtype(x: Scalar64) -> u64 {
+    // CHECK: %0 = alloca i64
+    // CHECK: store i64 %x, ptr %0
+    // CHECK: %1 = load i64, ptr %0
+    // CHECK: ret i64 %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_pair(
+#[no_mangle]
+pub unsafe fn check_to_pair(x: u64) -> Option<i32> {
+    // CHECK: %0 = alloca { i32, i32 }, align 4
+    // CHECK: store i64 %x, ptr %0, align 4
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_pair(
+#[no_mangle]
+pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
+    // The two arguments are of types that are only 4-aligned, but they're
+    // immediates so we can write using the destination alloca's alignment.
+    const { assert!(std::mem::align_of::<Option<i32>>() == 4) };
+
+    // CHECK: %0 = alloca i64, align 8
+    // CHECK: store i32 %x.0, ptr %1, align 8
+    // CHECK: store i32 %x.1, ptr %2, align 4
+    // CHECK: %3 = load i64, ptr %0, align 8
+    // CHECK: ret i64 %3
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_float(
+#[no_mangle]
+pub unsafe fn check_to_float(x: u32) -> f32 {
+    // CHECK: %0 = alloca float
+    // CHECK: store i32 %x, ptr %0
+    // CHECK: %1 = load float, ptr %0
+    // CHECK: ret float %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_float(
+#[no_mangle]
+pub unsafe fn check_from_float(x: f32) -> u32 {
+    // CHECK: %0 = alloca i32
+    // CHECK: store float %x, ptr %0
+    // CHECK: %1 = load i32, ptr %0
+    // CHECK: ret i32 %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_bytes(
+#[no_mangle]
+pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] {
+    // CHECK: %0 = alloca [4 x i8], align 1
+    // CHECK: store i32 %x, ptr %0, align 1
+    // CHECK: %1 = load i32, ptr %0, align 1
+    // CHECK: ret i32 %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_bytes(
+#[no_mangle]
+pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 {
+    // CHECK: %1 = alloca i32, align 4
+    // CHECK: %x = alloca [4 x i8], align 1
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false)
+    // CHECK: %3 = load i32, ptr %1, align 4
+    // CHECK: ret i32 %3
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_to_aggregate(
+#[no_mangle]
+pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 {
+    // CHECK: %0 = alloca %Aggregate64, align 4
+    // CHECK: store i64 %x, ptr %0, align 4
+    // CHECK: %1 = load i64, ptr %0, align 4
+    // CHECK: ret i64 %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_aggregate(
+#[no_mangle]
+pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 {
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false)
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_long_array_less_aligned(
+#[no_mangle]
+pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] {
+    // CHECK-NEXT: start
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false)
+    // CHECK-NEXT: ret void
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_long_array_more_aligned(
+#[no_mangle]
+pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] {
+    // CHECK-NEXT: start
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false)
+    // CHECK-NEXT: ret void
+    transmute(x)
+}
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index 260dcbac0fc..4d7a80bfbe5 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -1,13 +1,19 @@
 // compile-flags: -O -C no-prepopulate-passes
+// min-llvm-version: 15.0 # this test assumes `ptr`s and thus no `pointercast`s
 
 #![crate_type = "lib"]
 
-// FIXME(eddyb) all of these tests show memory stores and loads, even after a
-// scalar `bitcast`, more special-casing is required to remove `alloca` usage.
+// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
+// without needing to pointercast, and SRoA will turn that into a `bitcast`.
+// As such, there's no longer special-casing in `transmute` to attempt to
+// generate `bitcast` ourselves, as that just made the IR longer.
+
+// FIXME: That said, `bitcast`s could still be a valuable addition if they could
+// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely.
 
 // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x)
-// CHECK: store i32 %{{.*}}, {{.*}} %0
-// CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0
+// CHECK: store float %{{.*}}, ptr %0
+// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0
 // CHECK: ret i32 %[[RES]]
 #[no_mangle]
 pub fn f32_to_bits(x: f32) -> u32 {
@@ -25,12 +31,10 @@ pub fn bool_to_byte(b: bool) -> u8 {
 }
 
 // CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte)
-// CHECK: %1 = trunc i8 %byte to i1
-// CHECK-NEXT: %2 = zext i1 %1 to i8
-// CHECK-NEXT: store i8 %2, {{.*}} %0
-// CHECK-NEXT: %3 = load i8, {{.*}} %0
-// CHECK-NEXT: %4 = trunc i8 %3 to i1
-// CHECK: ret i1 %4
+// CHECK: store i8 %byte, ptr %0
+// CHECK-NEXT: %1 = load i8, {{.*}} %0
+// CHECK-NEXT: %2 = trunc i8 %1 to i1
+// CHECK: ret i1 %2
 #[no_mangle]
 pub unsafe fn byte_to_bool(byte: u8) -> bool {
     std::mem::transmute(byte)
@@ -45,20 +49,8 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
     unsafe { std::mem::transmute(p) }
 }
 
-// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are
-// currently not special-cased like other scalar `transmute`s, because
-// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`.
-//
-// Tests below show the non-special-cased behavior (with the possible
-// future special-cased instructions in the "NOTE(eddyb)" comments).
-
 // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p)
-
-// NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
-//        %2 = ptrtoint i16* %p to [[USIZE]]
-//             store [[USIZE]] %2, [[USIZE]]* %0
 // CHECK: store {{i16\*|ptr}} %p, {{.*}}
-
 // CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0
 // CHECK: ret [[USIZE]] %[[RES]]
 #[no_mangle]
@@ -67,12 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
 }
 
 // CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i)
-
-// NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
-//        %2 = inttoptr [[USIZE]] %i to i16*
-//             store i16* %2, i16** %0
 // CHECK: store [[USIZE]] %i, {{.*}}
-
 // CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0
 // CHECK: ret {{i16\*|ptr}} %[[RES]]
 #[no_mangle]
diff --git a/tests/mir-opt/building/shifts.rs b/tests/mir-opt/building/shifts.rs
new file mode 100644
index 00000000000..4b63a00a304
--- /dev/null
+++ b/tests/mir-opt/building/shifts.rs
@@ -0,0 +1,20 @@
+// compile-flags: -C debug-assertions=yes
+
+// EMIT_MIR shifts.shift_signed.built.after.mir
+fn shift_signed(small: i8, big: u128, a: i8, b: i32, c: i128) -> ([i8; 3], [u128; 3]) {
+    (
+        [small >> a, small >> b, small >> c],
+        [big << a, big << b, big << c],
+    )
+}
+
+// EMIT_MIR shifts.shift_unsigned.built.after.mir
+fn shift_unsigned(small: u8, big: i128, a: u8, b: u32, c: u128) -> ([u8; 3], [i128; 3]) {
+    (
+        [small >> a, small >> b, small >> c],
+        [big << a, big << b, big << c],
+    )
+}
+
+fn main() {
+}
diff --git a/tests/mir-opt/building/shifts.shift_signed.built.after.mir b/tests/mir-opt/building/shifts.shift_signed.built.after.mir
new file mode 100644
index 00000000000..028777cefdd
--- /dev/null
+++ b/tests/mir-opt/building/shifts.shift_signed.built.after.mir
@@ -0,0 +1,147 @@
+// MIR for `shift_signed` after built
+
+fn shift_signed(_1: i8, _2: u128, _3: i8, _4: i32, _5: i128) -> ([i8; 3], [u128; 3]) {
+    debug small => _1;                   // in scope 0 at $DIR/shifts.rs:+0:17: +0:22
+    debug big => _2;                     // in scope 0 at $DIR/shifts.rs:+0:28: +0:31
+    debug a => _3;                       // in scope 0 at $DIR/shifts.rs:+0:39: +0:40
+    debug b => _4;                       // in scope 0 at $DIR/shifts.rs:+0:46: +0:47
+    debug c => _5;                       // in scope 0 at $DIR/shifts.rs:+0:54: +0:55
+    let mut _0: ([i8; 3], [u128; 3]);    // return place in scope 0 at $DIR/shifts.rs:+0:66: +0:86
+    let mut _6: [i8; 3];                 // in scope 0 at $DIR/shifts.rs:+2:9: +2:45
+    let mut _7: i8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _8: i8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:15
+    let mut _9: i8;                      // in scope 0 at $DIR/shifts.rs:+2:19: +2:20
+    let mut _10: u8;                     // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _11: bool;                   // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _12: i8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _13: i8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:27
+    let mut _14: i32;                    // in scope 0 at $DIR/shifts.rs:+2:31: +2:32
+    let mut _15: u32;                    // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _16: bool;                   // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _17: i8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _18: i8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:39
+    let mut _19: i128;                   // in scope 0 at $DIR/shifts.rs:+2:43: +2:44
+    let mut _20: u128;                   // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _21: bool;                   // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _22: [u128; 3];              // in scope 0 at $DIR/shifts.rs:+3:9: +3:39
+    let mut _23: u128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _24: u128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:13
+    let mut _25: i8;                     // in scope 0 at $DIR/shifts.rs:+3:17: +3:18
+    let mut _26: u8;                     // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _27: bool;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _28: u128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _29: u128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:23
+    let mut _30: i32;                    // in scope 0 at $DIR/shifts.rs:+3:27: +3:28
+    let mut _31: u32;                    // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _32: bool;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _33: u128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    let mut _34: u128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:33
+    let mut _35: i128;                   // in scope 0 at $DIR/shifts.rs:+3:37: +3:38
+    let mut _36: u128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    let mut _37: bool;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+
+    bb0: {
+        StorageLive(_6);                 // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageLive(_7);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageLive(_8);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        _8 = _1;                         // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        StorageLive(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _9 = _3;                         // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _10 = _9 as u8 (IntToInt);       // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        _11 = Lt(move _10, const 8_u8);  // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        assert(move _11, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    }
+
+    bb1: {
+        _7 = Shr(move _8, move _9);      // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageDead(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageDead(_8);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageLive(_12);                // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageLive(_13);                // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        _13 = _1;                        // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        StorageLive(_14);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _14 = _4;                        // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _15 = _14 as u32 (IntToInt);     // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        _16 = Lt(move _15, const 8_u32); // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        assert(move _16, "attempt to shift right by `{}`, which would overflow", _14) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    }
+
+    bb2: {
+        _12 = Shr(move _13, move _14);   // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageDead(_14);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageDead(_13);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageLive(_17);                // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageLive(_18);                // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        _18 = _1;                        // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        StorageLive(_19);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _19 = _5;                        // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _20 = _19 as u128 (IntToInt);    // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        _21 = Lt(move _20, const 8_u128); // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        assert(move _21, "attempt to shift right by `{}`, which would overflow", _19) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    }
+
+    bb3: {
+        _17 = Shr(move _18, move _19);   // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageDead(_19);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        StorageDead(_18);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _6 = [move _7, move _12, move _17]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageDead(_17);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_12);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_7);                 // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageLive(_22);                // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageLive(_23);                // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageLive(_24);                // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        _24 = _2;                        // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        StorageLive(_25);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _25 = _3;                        // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _26 = _25 as u8 (IntToInt);      // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        _27 = Lt(move _26, const 128_u8); // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        assert(move _27, "attempt to shift left by `{}`, which would overflow", _25) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    }
+
+    bb4: {
+        _23 = Shl(move _24, move _25);   // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageDead(_25);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageDead(_24);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageLive(_28);                // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageLive(_29);                // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        _29 = _2;                        // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        StorageLive(_30);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _30 = _4;                        // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _31 = _30 as u32 (IntToInt);     // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        _32 = Lt(move _31, const 128_u32); // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        assert(move _32, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    }
+
+    bb5: {
+        _28 = Shl(move _29, move _30);   // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageDead(_30);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageDead(_29);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageLive(_33);                // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageLive(_34);                // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        _34 = _2;                        // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        StorageLive(_35);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _35 = _5;                        // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _36 = _35 as u128 (IntToInt);    // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        _37 = Lt(move _36, const 128_u128); // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        assert(move _37, "attempt to shift left by `{}`, which would overflow", _35) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    }
+
+    bb6: {
+        _33 = Shl(move _34, move _35);   // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageDead(_35);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        StorageDead(_34);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _22 = [move _23, move _28, move _33]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageDead(_33);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_28);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_23);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        _0 = (move _6, move _22);        // scope 0 at $DIR/shifts.rs:+1:5: +4:6
+        StorageDead(_22);                // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        StorageDead(_6);                 // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        return;                          // scope 0 at $DIR/shifts.rs:+5:2: +5:2
+    }
+
+    bb7 (cleanup): {
+        resume;                          // scope 0 at $DIR/shifts.rs:+0:1: +5:2
+    }
+}
diff --git a/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir
new file mode 100644
index 00000000000..04da2d20d24
--- /dev/null
+++ b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir
@@ -0,0 +1,135 @@
+// MIR for `shift_unsigned` after built
+
+fn shift_unsigned(_1: u8, _2: i128, _3: u8, _4: u32, _5: u128) -> ([u8; 3], [i128; 3]) {
+    debug small => _1;                   // in scope 0 at $DIR/shifts.rs:+0:19: +0:24
+    debug big => _2;                     // in scope 0 at $DIR/shifts.rs:+0:30: +0:33
+    debug a => _3;                       // in scope 0 at $DIR/shifts.rs:+0:41: +0:42
+    debug b => _4;                       // in scope 0 at $DIR/shifts.rs:+0:48: +0:49
+    debug c => _5;                       // in scope 0 at $DIR/shifts.rs:+0:56: +0:57
+    let mut _0: ([u8; 3], [i128; 3]);    // return place in scope 0 at $DIR/shifts.rs:+0:68: +0:88
+    let mut _6: [u8; 3];                 // in scope 0 at $DIR/shifts.rs:+2:9: +2:45
+    let mut _7: u8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _8: u8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:15
+    let mut _9: u8;                      // in scope 0 at $DIR/shifts.rs:+2:19: +2:20
+    let mut _10: bool;                   // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _11: u8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _12: u8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:27
+    let mut _13: u32;                    // in scope 0 at $DIR/shifts.rs:+2:31: +2:32
+    let mut _14: bool;                   // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _15: u8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _16: u8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:39
+    let mut _17: u128;                   // in scope 0 at $DIR/shifts.rs:+2:43: +2:44
+    let mut _18: bool;                   // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _19: [i128; 3];              // in scope 0 at $DIR/shifts.rs:+3:9: +3:39
+    let mut _20: i128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _21: i128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:13
+    let mut _22: u8;                     // in scope 0 at $DIR/shifts.rs:+3:17: +3:18
+    let mut _23: bool;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _24: i128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _25: i128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:23
+    let mut _26: u32;                    // in scope 0 at $DIR/shifts.rs:+3:27: +3:28
+    let mut _27: bool;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _28: i128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    let mut _29: i128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:33
+    let mut _30: u128;                   // in scope 0 at $DIR/shifts.rs:+3:37: +3:38
+    let mut _31: bool;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+
+    bb0: {
+        StorageLive(_6);                 // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageLive(_7);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageLive(_8);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        _8 = _1;                         // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        StorageLive(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _9 = _3;                         // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _10 = Lt(_9, const 8_u8);        // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        assert(move _10, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    }
+
+    bb1: {
+        _7 = Shr(move _8, move _9);      // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageDead(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageDead(_8);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageLive(_11);                // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageLive(_12);                // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        _12 = _1;                        // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        StorageLive(_13);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _13 = _4;                        // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _14 = Lt(_13, const 8_u32);      // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        assert(move _14, "attempt to shift right by `{}`, which would overflow", _13) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    }
+
+    bb2: {
+        _11 = Shr(move _12, move _13);   // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageDead(_13);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageDead(_12);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageLive(_15);                // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageLive(_16);                // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        _16 = _1;                        // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        StorageLive(_17);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _17 = _5;                        // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _18 = Lt(_17, const 8_u128);     // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        assert(move _18, "attempt to shift right by `{}`, which would overflow", _17) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    }
+
+    bb3: {
+        _15 = Shr(move _16, move _17);   // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageDead(_17);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        StorageDead(_16);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _6 = [move _7, move _11, move _15]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageDead(_15);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_11);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_7);                 // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageLive(_19);                // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageLive(_20);                // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageLive(_21);                // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        _21 = _2;                        // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        StorageLive(_22);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _22 = _3;                        // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _23 = Lt(_22, const 128_u8);     // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        assert(move _23, "attempt to shift left by `{}`, which would overflow", _22) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    }
+
+    bb4: {
+        _20 = Shl(move _21, move _22);   // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageDead(_22);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageDead(_21);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageLive(_24);                // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageLive(_25);                // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        _25 = _2;                        // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        StorageLive(_26);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _26 = _4;                        // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _27 = Lt(_26, const 128_u32);    // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        assert(move _27, "attempt to shift left by `{}`, which would overflow", _26) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    }
+
+    bb5: {
+        _24 = Shl(move _25, move _26);   // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageDead(_26);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageDead(_25);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageLive(_28);                // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageLive(_29);                // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        _29 = _2;                        // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        StorageLive(_30);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _30 = _5;                        // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _31 = Lt(_30, const 128_u128);   // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        assert(move _31, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    }
+
+    bb6: {
+        _28 = Shl(move _29, move _30);   // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageDead(_30);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        StorageDead(_29);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _19 = [move _20, move _24, move _28]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageDead(_28);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_24);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_20);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        _0 = (move _6, move _19);        // scope 0 at $DIR/shifts.rs:+1:5: +4:6
+        StorageDead(_19);                // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        StorageDead(_6);                 // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        return;                          // scope 0 at $DIR/shifts.rs:+5:2: +5:2
+    }
+
+    bb7 (cleanup): {
+        resume;                          // scope 0 at $DIR/shifts.rs:+0:1: +5:2
+    }
+}
diff --git a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff
new file mode 100644
index 00000000000..933dfbb5166
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff
@@ -0,0 +1,15 @@
+- // MIR for `from_char` before ConstProp
++ // MIR for `from_char` after ConstProp
+  
+  fn from_char() -> i32 {
+      let mut _0: i32;                     // return place in scope 0 at $DIR/transmute.rs:+0:23: +0:26
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 'R' as i32 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:28
++         _0 = const 82_i32;               // scope 1 at $DIR/transmute.rs:+1:14: +1:28
+          return;                          // scope 0 at $DIR/transmute.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff
new file mode 100644
index 00000000000..f3474855f02
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff
@@ -0,0 +1,14 @@
+- // MIR for `invalid_bool` before ConstProp
++ // MIR for `invalid_bool` after ConstProp
+  
+  fn invalid_bool() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37
+      scope 1 {
+      }
+  
+      bb0: {
+          _0 = const -1_i8 as bool (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:30
+          return;                          // scope 0 at $DIR/transmute.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff
new file mode 100644
index 00000000000..ba087e226c9
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff
@@ -0,0 +1,14 @@
+- // MIR for `invalid_char` before ConstProp
++ // MIR for `invalid_char` after ConstProp
+  
+  fn invalid_char() -> char {
+      let mut _0: char;                    // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37
+      scope 1 {
+      }
+  
+      bb0: {
+          _0 = const _ as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33
+          return;                          // scope 0 at $DIR/transmute.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff
new file mode 100644
index 00000000000..76d464789c1
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff
@@ -0,0 +1,23 @@
+- // MIR for `less_as_i8` before ConstProp
++ // MIR for `less_as_i8` after ConstProp
+  
+  fn less_as_i8() -> i8 {
+      let mut _0: i8;                      // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:26
+      let mut _1: std::cmp::Ordering;      // in scope 0 at $DIR/transmute.rs:+1:24: +1:48
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 1 at $DIR/transmute.rs:+1:24: +1:48
+-         _1 = Less;                       // scope 1 at $DIR/transmute.rs:+1:24: +1:48
+-         _0 = move _1 as i8 (Transmute);  // scope 1 at $DIR/transmute.rs:+1:14: +1:49
++         _1 = const Less;                 // scope 1 at $DIR/transmute.rs:+1:24: +1:48
++                                          // mir::Constant
++                                          // + span: no-location
++                                          // + literal: Const { ty: std::cmp::Ordering, val: Value(Scalar(0xff)) }
++         _0 = const -1_i8;                // scope 1 at $DIR/transmute.rs:+1:14: +1:49
+          StorageDead(_1);                 // scope 1 at $DIR/transmute.rs:+1:48: +1:49
+          return;                          // scope 0 at $DIR/transmute.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs
new file mode 100644
index 00000000000..b753cdccd60
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.rs
@@ -0,0 +1,61 @@
+// unit-test: ConstProp
+// compile-flags: -O --crate-type=lib
+
+use std::mem::transmute;
+
+// EMIT_MIR transmute.less_as_i8.ConstProp.diff
+pub fn less_as_i8() -> i8 {
+    unsafe { transmute(std::cmp::Ordering::Less) }
+}
+
+// EMIT_MIR transmute.from_char.ConstProp.diff
+pub fn from_char() -> i32 {
+    unsafe { transmute('R') }
+}
+
+// EMIT_MIR transmute.valid_char.ConstProp.diff
+pub fn valid_char() -> char {
+    unsafe { transmute(0x52_u32) }
+}
+
+// EMIT_MIR transmute.invalid_char.ConstProp.diff
+pub unsafe fn invalid_char() -> char {
+    unsafe { transmute(i32::MAX) }
+}
+
+// EMIT_MIR transmute.invalid_bool.ConstProp.diff
+pub unsafe fn invalid_bool() -> bool {
+    unsafe { transmute(-1_i8) }
+}
+
+// EMIT_MIR transmute.undef_union_as_integer.ConstProp.diff
+pub unsafe fn undef_union_as_integer() -> u32 {
+    union Union32 { value: u32, unit: () }
+    unsafe { transmute(Union32 { unit: () }) }
+}
+
+// EMIT_MIR transmute.unreachable_direct.ConstProp.diff
+pub unsafe fn unreachable_direct() -> ! {
+    let x: Never = unsafe { transmute(()) };
+    match x {}
+}
+
+// EMIT_MIR transmute.unreachable_ref.ConstProp.diff
+pub unsafe fn unreachable_ref() -> ! {
+    let x: &Never = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+// EMIT_MIR transmute.unreachable_mut.ConstProp.diff
+pub unsafe fn unreachable_mut() -> ! {
+    let x: &mut Never = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+// EMIT_MIR transmute.unreachable_box.ConstProp.diff
+pub unsafe fn unreachable_box() -> ! {
+    let x: Box<Never> = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+enum Never {}
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff
new file mode 100644
index 00000000000..538b1f26e4c
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff
@@ -0,0 +1,22 @@
+- // MIR for `undef_union_as_integer` before ConstProp
++ // MIR for `undef_union_as_integer` after ConstProp
+  
+  fn undef_union_as_integer() -> u32 {
+      let mut _0: u32;                     // return place in scope 0 at $DIR/transmute.rs:+0:43: +0:46
+      let mut _1: undef_union_as_integer::Union32; // in scope 0 at $DIR/transmute.rs:+2:24: +2:44
+      let mut _2: ();                      // in scope 0 at $DIR/transmute.rs:+2:40: +2:42
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 1 at $DIR/transmute.rs:+2:24: +2:44
+          StorageLive(_2);                 // scope 1 at $DIR/transmute.rs:+2:40: +2:42
+          _2 = ();                         // scope 1 at $DIR/transmute.rs:+2:40: +2:42
+          _1 = Union32 { value: move _2 }; // scope 1 at $DIR/transmute.rs:+2:24: +2:44
+          StorageDead(_2);                 // scope 1 at $DIR/transmute.rs:+2:43: +2:44
+          _0 = move _1 as u32 (Transmute); // scope 1 at $DIR/transmute.rs:+2:14: +2:45
+          StorageDead(_1);                 // scope 1 at $DIR/transmute.rs:+2:44: +2:45
+          return;                          // scope 0 at $DIR/transmute.rs:+3:2: +3:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff
new file mode 100644
index 00000000000..8bf97996a67
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff
@@ -0,0 +1,23 @@
+- // MIR for `unreachable_box` before ConstProp
++ // MIR for `unreachable_box` after ConstProp
+  
+  fn unreachable_box() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37
+      let mut _1: !;                       // in scope 0 at $DIR/transmute.rs:+0:38: +3:2
+      let _2: std::boxed::Box<Never>;      // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
+      let mut _3: !;                       // in scope 0 at $DIR/transmute.rs:+2:5: +2:16
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/transmute.rs:+0:38: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/transmute.rs:+1:9: +1:10
+          _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52
+          StorageLive(_3);                 // scope 1 at $DIR/transmute.rs:+2:5: +2:16
+          unreachable;                     // scope 1 at $DIR/transmute.rs:+2:11: +2:13
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff
new file mode 100644
index 00000000000..81b7b368993
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff
@@ -0,0 +1,25 @@
+- // MIR for `unreachable_direct` before ConstProp
++ // MIR for `unreachable_direct` after ConstProp
+  
+  fn unreachable_direct() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40
+      let mut _1: !;                       // in scope 0 at $DIR/transmute.rs:+0:41: +3:2
+      let _2: Never;                       // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
+      let mut _3: ();                      // in scope 0 at $DIR/transmute.rs:+1:39: +1:41
+      let mut _4: !;                       // in scope 0 at $DIR/transmute.rs:+2:5: +2:15
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/transmute.rs:+0:41: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/transmute.rs:+1:9: +1:10
+          StorageLive(_3);                 // scope 2 at $DIR/transmute.rs:+1:39: +1:41
+          _3 = ();                         // scope 2 at $DIR/transmute.rs:+1:39: +1:41
+          _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42
+          unreachable;                     // scope 2 at $DIR/transmute.rs:+1:29: +1:42
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff
new file mode 100644
index 00000000000..34f7aea8ed2
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff
@@ -0,0 +1,27 @@
+- // MIR for `unreachable_mut` before ConstProp
++ // MIR for `unreachable_mut` after ConstProp
+  
+  fn unreachable_mut() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37
+      let mut _1: !;                       // in scope 0 at $DIR/transmute.rs:+0:38: +3:2
+      let _2: &mut Never;                  // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
+      let mut _3: &mut Never;              // in scope 0 at $DIR/transmute.rs:+1:34: +1:52
+      let mut _4: !;                       // in scope 0 at $DIR/transmute.rs:+2:5: +2:16
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/transmute.rs:+0:38: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/transmute.rs:+1:9: +1:10
+          StorageLive(_3);                 // scope 0 at $DIR/transmute.rs:+1:34: +1:52
+          _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52
+          _2 = &mut (*_3);                 // scope 0 at $DIR/transmute.rs:+1:34: +1:52
+          StorageDead(_3);                 // scope 0 at $DIR/transmute.rs:+1:54: +1:55
+          StorageLive(_4);                 // scope 1 at $DIR/transmute.rs:+2:5: +2:16
+          unreachable;                     // scope 1 at $DIR/transmute.rs:+2:11: +2:13
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff
new file mode 100644
index 00000000000..ff95f2a0b94
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff
@@ -0,0 +1,23 @@
+- // MIR for `unreachable_ref` before ConstProp
++ // MIR for `unreachable_ref` after ConstProp
+  
+  fn unreachable_ref() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37
+      let mut _1: !;                       // in scope 0 at $DIR/transmute.rs:+0:38: +3:2
+      let _2: &Never;                      // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
+      let mut _3: !;                       // in scope 0 at $DIR/transmute.rs:+2:5: +2:16
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/transmute.rs:+0:38: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/transmute.rs:+1:9: +1:10
+          _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48
+          StorageLive(_3);                 // scope 1 at $DIR/transmute.rs:+2:5: +2:16
+          unreachable;                     // scope 1 at $DIR/transmute.rs:+2:11: +2:13
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff
new file mode 100644
index 00000000000..eac33b73003
--- /dev/null
+++ b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff
@@ -0,0 +1,15 @@
+- // MIR for `valid_char` before ConstProp
++ // MIR for `valid_char` after ConstProp
+  
+  fn valid_char() -> char {
+      let mut _0: char;                    // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:28
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 82_u32 as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33
++         _0 = const 'R';                  // scope 1 at $DIR/transmute.rs:+1:14: +1:33
+          return;                          // scope 0 at $DIR/transmute.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff
index fb0b3866e69..b377a65b964 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff
@@ -12,9 +12,9 @@
       let mut _7: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
       let mut _8: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _9: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-      let mut _10: i32;                    // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+      let mut _10: u32;                    // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _11: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-      let mut _12: i32;                    // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+      let mut _12: u32;                    // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       let mut _13: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:14:5: 14:17
           debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
@@ -43,24 +43,24 @@
           StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
--         _10 = BitAnd(const 8_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
--         _11 = Ne(move _10, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
--         assert(!move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-+         _10 = const 0_i32;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-+         _11 = const false;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-+         assert(!const false, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         _10 = const 8_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         _11 = Lt(move _10, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         _10 = const 8_u32;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         _11 = const true;                // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         assert(const true, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       }
   
       bb1: {
           _8 = Shr(_1, const 8_i32);       // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
           _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageDead(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
--         _12 = BitAnd(const 1_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
--         _13 = Ne(move _12, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
--         assert(!move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-+         _12 = const 0_i32;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-+         _13 = const false;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-+         assert(!const false, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         _12 = const 1_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         _13 = Lt(move _12, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         assert(move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         _12 = const 1_u32;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         _13 = const true;                // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         assert(const true, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       }
   
       bb2: {
diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
index bcda1288045..8e6e6fc0ec2 100644
--- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
+++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
@@ -24,61 +24,49 @@
           StorageLive(_2);                 // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15
           StorageLive(_3);                 // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
           _3 = _1;                         // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
-          _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
-                                           // mir::Constant
-                                           // + span: $DIR/issue_75439.rs:8:37: 8:46
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
+          _2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
+          StorageDead(_3);                 // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
+          switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
-          switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
       bb2: {
-          switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
       bb3: {
-          switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
-      }
-  
-      bb4: {
           StorageLive(_5);                 // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38
           StorageLive(_6);                 // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
           _6 = _4;                         // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
-          _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
-                                           // mir::Constant
-                                           // + span: $DIR/issue_75439.rs:11:23: 11:32
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
+          _5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
+          StorageDead(_6);                 // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
+          _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
+          StorageDead(_5);                 // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
+          StorageDead(_4);                 // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
+          goto -> bb7;                     // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
       }
   
-      bb5: {
+      bb4: {
           StorageLive(_4);                 // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
           _4 = _2[3 of 4];                 // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
-          goto -> bb4;                     // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          goto -> bb3;                     // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
-      bb6: {
+      bb5: {
           StorageLive(_4);                 // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
           _4 = _2[3 of 4];                 // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
-          goto -> bb4;                     // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
+          goto -> bb3;                     // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
       }
   
-      bb7: {
-          StorageDead(_6);                 // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
-          _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
-          StorageDead(_5);                 // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
-          StorageDead(_4);                 // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
-          goto -> bb9;                     // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
-      }
-  
-      bb8: {
+      bb6: {
           _0 = Option::<[u8; 4]>::None;    // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
-          goto -> bb9;                     // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
+          goto -> bb7;                     // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
       }
   
-      bb9: {
+      bb7: {
           StorageDead(_2);                 // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2
           return;                          // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2
       }
diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
index d9898d8e0f0..5c5a9e90a9d 100644
--- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
@@ -11,7 +11,7 @@
           StorageLive(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
 -         _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
+-                                          // + span: $DIR/lower_intrinsics.rs:105:9: 105:32
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
 +         assume(const true);              // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
 +         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
diff --git a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index d962ef8cb12..87960521bb4 100644
--- a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -31,7 +31,7 @@
           _3 = &(*_4);                     // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
 -         _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
+-                                          // + span: $DIR/lower_intrinsics.rs:82:5: 82:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
 +         _2 = discriminant((*_3));        // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
@@ -46,13 +46,13 @@
           StorageLive(_7);                 // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
           _19 = const _;                   // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:50:42: 50:44
+                                           // + span: $DIR/lower_intrinsics.rs:83:42: 83:44
                                            // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
           _7 = &(*_19);                    // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
           _6 = &(*_7);                     // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
+-                                          // + span: $DIR/lower_intrinsics.rs:83:5: 83:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
 +         _5 = discriminant((*_6));        // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 +         goto -> bb2;                     // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
@@ -67,13 +67,13 @@
           StorageLive(_11);                // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
           _18 = const _;                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:51:42: 51:45
+                                           // + span: $DIR/lower_intrinsics.rs:84:42: 84:45
                                            // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
           _11 = &(*_18);                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
           _10 = &(*_11);                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
+-                                          // + span: $DIR/lower_intrinsics.rs:84:5: 84:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
 +         _9 = discriminant((*_10));       // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 +         goto -> bb3;                     // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
@@ -88,13 +88,13 @@
           StorageLive(_15);                // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
           _17 = const _;                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:52:42: 52:47
+                                           // + span: $DIR/lower_intrinsics.rs:85:42: 85:47
                                            // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
           _15 = &(*_17);                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
           _14 = &(*_15);                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
+-                                          // + span: $DIR/lower_intrinsics.rs:85:5: 85:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
 +         _13 = discriminant((*_14));      // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 +         goto -> bb4;                     // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
index 5c972a00e46..15cce7f4a2c 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
@@ -49,7 +49,7 @@
           StorageDead(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
 -         _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:65:9: 65:28
+-                                          // + span: $DIR/lower_intrinsics.rs:98:9: 98:28
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
 +         copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
 +         goto -> bb1;                     // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
index e535141e772..c563703b250 100644
--- a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
@@ -24,7 +24,7 @@
           _4 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
 -         _3 = option_payload_ptr::<usize>(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:99:18: 99:54
+-                                          // + span: $DIR/lower_intrinsics.rs:132:18: 132:54
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) }
 +         _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
 +         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
@@ -37,7 +37,7 @@
           _6 = &raw const (*_2);           // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
 -         _5 = option_payload_ptr::<String>(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:100:18: 100:54
+-                                          // + span: $DIR/lower_intrinsics.rs:133:18: 133:54
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) }
 +         _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
 +         goto -> bb2;                     // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
index 27fceeedf6e..f2f676843b2 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
@@ -13,7 +13,7 @@
           _2 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
 -         _0 = read_via_copy::<i32>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:85:14: 85:45
+-                                          // + span: $DIR/lower_intrinsics.rs:118:14: 118:45
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) }
 +         _0 = (*_2);                      // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
 +         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
index 610c67d2fec..3ad21283fa4 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
@@ -13,7 +13,7 @@
           _2 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
 -         _0 = read_via_copy::<Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:90:14: 90:45
+-                                          // + span: $DIR/lower_intrinsics.rs:123:14: 123:45
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) }
 +         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
       }
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index f07e2816f4f..ec215c9a664 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -38,6 +38,39 @@ pub fn non_const<T>() -> usize {
     size_of_t()
 }
 
+// EMIT_MIR lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
+pub fn transmute_inhabited(c: std::cmp::Ordering) -> i8 {
+    unsafe { std::mem::transmute(c) }
+}
+
+// EMIT_MIR lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
+pub unsafe fn transmute_uninhabited(u: ()) -> Never {
+    unsafe { std::mem::transmute::<(), Never>(u) }
+}
+
+// EMIT_MIR lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
+pub unsafe fn transmute_ref_dst<T: ?Sized>(u: &T) -> *const T {
+    unsafe { std::mem::transmute(u) }
+}
+
+// EMIT_MIR lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
+pub unsafe fn transmute_to_ref_uninhabited() -> ! {
+    let x: &Never = std::mem::transmute(1usize);
+    match *x {}
+}
+
+// EMIT_MIR lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
+pub unsafe fn transmute_to_mut_uninhabited() -> ! {
+    let x: &mut Never = std::mem::transmute(1usize);
+    match *x {}
+}
+
+// EMIT_MIR lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
+pub unsafe fn transmute_to_box_uninhabited() -> ! {
+    let x: Box<Never> = std::mem::transmute(1usize);
+    match *x {}
+}
+
 pub enum E {
     A,
     B,
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
new file mode 100644
index 00000000000..814368ec021
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
@@ -0,0 +1,27 @@
+- // MIR for `transmute_inhabited` before LowerIntrinsics
++ // MIR for `transmute_inhabited` after LowerIntrinsics
+  
+  fn transmute_inhabited(_1: std::cmp::Ordering) -> i8 {
+      debug c => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:28: +0:29
+      let mut _0: i8;                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:56
+      let mut _2: std::cmp::Ordering;      // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
+          _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
+-         _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:43:14: 43:33
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::<std::cmp::Ordering, i8>}, val: Value(<ZST>) }
++         _0 = move _2 as i8 (Transmute);  // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+      }
+  
+      bb1: {
+          StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
new file mode 100644
index 00000000000..5440c7a4c8e
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
@@ -0,0 +1,27 @@
+- // MIR for `transmute_ref_dst` before LowerIntrinsics
++ // MIR for `transmute_ref_dst` after LowerIntrinsics
+  
+  fn transmute_ref_dst(_1: &T) -> *const T {
+      debug u => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:45
+      let mut _0: *const T;                // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:62
+      let mut _2: &T;                      // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
+          _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
+-         _0 = transmute::<&T, *const T>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:53:14: 53:33
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value(<ZST>) }
++         _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+      }
+  
+      bb1: {
+          StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
new file mode 100644
index 00000000000..43ddccc1ef7
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
@@ -0,0 +1,29 @@
+- // MIR for `transmute_to_box_uninhabited` before LowerIntrinsics
++ // MIR for `transmute_to_box_uninhabited` after LowerIntrinsics
+  
+  fn transmute_to_box_uninhabited() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50
+      let mut _1: !;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
+      let _2: std::boxed::Box<Never>;      // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+      let mut _3: !;                       // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+-         _2 = transmute::<usize, Box<Never>>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:70:25: 70:44
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) }
++         _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
++         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+      }
+  
+      bb1: {
+          StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16
+          unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
new file mode 100644
index 00000000000..bf529a9ca67
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
@@ -0,0 +1,29 @@
+- // MIR for `transmute_to_mut_uninhabited` before LowerIntrinsics
++ // MIR for `transmute_to_mut_uninhabited` after LowerIntrinsics
+  
+  fn transmute_to_mut_uninhabited() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50
+      let mut _1: !;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
+      let _2: &mut Never;                  // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+      let mut _3: !;                       // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+-         _2 = transmute::<usize, &mut Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:64:25: 64:44
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) }
++         _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
++         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+      }
+  
+      bb1: {
+          StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16
+          unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
new file mode 100644
index 00000000000..4940a99021f
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
@@ -0,0 +1,29 @@
+- // MIR for `transmute_to_ref_uninhabited` before LowerIntrinsics
++ // MIR for `transmute_to_ref_uninhabited` after LowerIntrinsics
+  
+  fn transmute_to_ref_uninhabited() -> ! {
+      let mut _0: !;                       // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50
+      let mut _1: !;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
+      let _2: &Never;                      // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+      let mut _3: !;                       // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16
+      scope 1 {
+          debug x => _2;                   // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
+          StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
+-         _2 = transmute::<usize, &Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:58:21: 58:40
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) }
++         _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
++         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
+      }
+  
+      bb1: {
+          StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16
+          unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
new file mode 100644
index 00000000000..f3a12b9ba5f
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
@@ -0,0 +1,22 @@
+- // MIR for `transmute_uninhabited` before LowerIntrinsics
++ // MIR for `transmute_uninhabited` after LowerIntrinsics
+  
+  fn transmute_uninhabited(_1: ()) -> Never {
+      debug u => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:+0:37: +0:38
+      let mut _0: Never;                   // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:47: +0:52
+      let mut _2: ();                      // in scope 0 at $DIR/lower_intrinsics.rs:+1:47: +1:48
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
+          _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
+-         _0 = transmute::<(), Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:48:14: 48:46
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value(<ZST>) }
++         _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
++         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff
index 9870a70dec5..3b9a41249a4 100644
--- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff
@@ -32,7 +32,7 @@
           _5 = _2;                         // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54
 -         _3 = add_with_overflow::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:78:14: 78:49
+-                                          // + span: $DIR/lower_intrinsics.rs:111:14: 111:49
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::<i32>}, val: Value(<ZST>) }
 +         _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
@@ -48,7 +48,7 @@
           _8 = _2;                         // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54
 -         _6 = sub_with_overflow::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:79:14: 79:49
+-                                          // + span: $DIR/lower_intrinsics.rs:112:14: 112:49
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::<i32>}, val: Value(<ZST>) }
 +         _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
 +         goto -> bb2;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
@@ -64,7 +64,7 @@
           _11 = _2;                        // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54
 -         _9 = mul_with_overflow::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:80:14: 80:49
+-                                          // + span: $DIR/lower_intrinsics.rs:113:14: 113:49
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::<i32>}, val: Value(<ZST>) }
 +         _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
 +         goto -> bb3;                     // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
diff --git a/tests/run-make/issue-36710/Makefile b/tests/run-make/issue-36710/Makefile
index d6145c07126..c6b71f5fbd4 100644
--- a/tests/run-make/issue-36710/Makefile
+++ b/tests/run-make/issue-36710/Makefile
@@ -4,6 +4,7 @@
 # ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std`
 # ignore-musl FIXME: this makefile needs teaching how to use a musl toolchain
 #                    (see dist-i586-gnu-i586-i686-musl Dockerfile)
+# ignore-sgx
 
 include ../../run-make-fulldeps/tools.mk
 
diff --git a/tests/run-make/raw-dylib-cross-compilation/Makefile b/tests/run-make/raw-dylib-cross-compilation/Makefile
new file mode 100644
index 00000000000..2a714f3a11f
--- /dev/null
+++ b/tests/run-make/raw-dylib-cross-compilation/Makefile
@@ -0,0 +1,22 @@
+# Tests that raw-dylib cross compilation works correctly
+
+# only-gnu
+# needs-i686-dlltool
+# needs-x86_64-dlltool
+
+# i686 dlltool.exe can't product x64 binaries.
+# ignore-i686-pc-windows-gnu
+
+include ../../run-make-fulldeps/tools.mk
+
+all:
+	# Build as x86 and make sure that we have x86 objects only.
+	$(RUSTC) --crate-type lib --crate-name i686_raw_dylib_test --target i686-pc-windows-gnu lib.rs
+	"$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libi686_raw_dylib_test.rlib > $(TMPDIR)/i686.objdump.txt
+	$(CGREP) "file format coff-i386" < $(TMPDIR)/i686.objdump.txt
+	$(CGREP) -v "file format coff-x86-64" < $(TMPDIR)/i686.objdump.txt
+	# Build as x64 and make sure that we have x64 objects only.
+	$(RUSTC) --crate-type lib --crate-name x64_raw_dylib_test --target x86_64-pc-windows-gnu lib.rs
+	"$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libx64_raw_dylib_test.rlib > $(TMPDIR)/x64.objdump.txt
+	$(CGREP) "file format coff-x86-64" < $(TMPDIR)/x64.objdump.txt
+	$(CGREP) -v "file format coff-i386" < $(TMPDIR)/x64.objdump.txt
diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs
new file mode 100644
index 00000000000..51bf2ec6b6e
--- /dev/null
+++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs
@@ -0,0 +1,20 @@
+#![feature(raw_dylib)]
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+// This is needed because of #![no_core]:
+#[lang = "sized"]
+trait Sized {}
+
+#[link(name = "extern_1", kind = "raw-dylib")]
+extern {
+    fn extern_fn();
+}
+
+pub fn extern_fn_caller() {
+    unsafe {
+        extern_fn();
+    }
+}
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks
index e839c200bbb..af9bc8c1d62 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks
+++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks
@@ -1,8 +1,7 @@
 CHECK: cc_plus_one_asm
 CHECK-NEXT: movl
 CHECK-NEXT: lfence
-CHECK-NEXT: inc
-CHECK-NEXT: notq (%rsp)
-CHECK-NEXT: notq (%rsp)
+CHECK-NEXT: incl
+CHECK-NEXT: shlq $0, (%rsp)
 CHECK-NEXT: lfence
 CHECK-NEXT: retq
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks
index 15211e3ade7..885bf461bf3 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks
+++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks
@@ -1,8 +1,24 @@
-CHECK: libunwind::Registers_x86_64::jumpto
+CHECK: __libunwind_Registers_x86_64_jumpto
 CHECK:      lfence
 CHECK:      lfence
 CHECK:      lfence
 CHECK:      lfence
-CHECK:      shlq    $0, (%rsp)
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK:      lfence
+CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
+CHECK-NEXT: lfence
+CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
 CHECK-NEXT: lfence
-CHECK-NEXT: retq
+CHECK-NEXT: jmpq *[[REGISTER]]
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks
index 0fe88141b24..8a5493650a7 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks
+++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks
@@ -2,6 +2,5 @@ CHECK: print
 CHECK:      lfence
 CHECK:      lfence
 CHECK:      lfence
-CHECK:      popq
 CHECK:      callq 0x{{[[:xdigit:]]*}} <_Unwind_Resume>
 CHECK-NEXT: ud2
diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh
index 944343df6e5..235bb603b84 100644
--- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh
+++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh
@@ -20,39 +20,38 @@ function build {
 }
 
 function check {
-    local func=$1
+    local func_re="$1"
     local checks="${TEST_DIR}/$2"
     local asm=$(mktemp)
-    local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump"
-    local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck"
-
-    ${objdump} --disassemble-symbols=${func} --demangle \
-      ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm}
+    local objdump="${LLVM_BIN_DIR}/llvm-objdump"
+    local filecheck="${LLVM_BIN_DIR}/FileCheck"
+    local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave
+
+    func="$(${objdump} --syms --demangle ${enclave} | \
+            grep --only-matching -E "[[:blank:]]+${func_re}\$" | \
+            sed -e 's/^[[:space:]]*//' )"
+    ${objdump} --disassemble-symbols="${func}" --demangle \
+      ${enclave} > ${asm}
     ${filecheck} --input-file ${asm} ${checks}
 }
 
 build
 
-check unw_getcontext unw_getcontext.checks
-check "libunwind::Registers_x86_64::jumpto()" jumpto.checks
-check "std::io::stdio::_print::h87f0c238421c45bc" print.checks
-check rust_plus_one_global_asm rust_plus_one_global_asm.checks \
-  || echo "warning: module level assembly currently not hardened"
+check "unw_getcontext" unw_getcontext.checks
+check "__libunwind_Registers_x86_64_jumpto" jumpto.checks
+check 'std::io::stdio::_print::[[:alnum:]]+' print.checks
+check rust_plus_one_global_asm rust_plus_one_global_asm.checks
 
 check cc_plus_one_c cc_plus_one_c.checks
 check cc_plus_one_c_asm cc_plus_one_c_asm.checks
 check cc_plus_one_cxx cc_plus_one_cxx.checks
 check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks
-check cc_plus_one_asm cc_plus_one_asm.checks \
-  || echo "warning: the cc crate forwards assembly files to the CC compiler." \
-           "Clang uses its own integrated assembler, which does not include the LVI passes."
+check cc_plus_one_asm cc_plus_one_asm.checks
 
 check cmake_plus_one_c cmake_plus_one_c.checks
 check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks
-check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks \
-  || echo "warning: module level assembly currently not hardened"
+check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks
 check cmake_plus_one_cxx cmake_plus_one_cxx.checks
 check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks
-check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks \
-  || echo "warning: module level assembly currently not hardened"
+check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks
 check cmake_plus_one_asm cmake_plus_one_asm.checks
diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js
index 98c6f27ca61..d1aa840ab08 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -17,6 +17,7 @@ const QUERY = [
     "a b:",
     "a (b:",
     "_:",
+    "_:a",
     "a-bb",
     "a>bb",
     "ab'",
@@ -48,7 +49,6 @@ const PARSED = [
         foundElems: 0,
         original: "<P>",
         returned: [],
-        typeFilter: -1,
         userQuery: "<p>",
         error: "Found generics without a path",
     },
@@ -57,7 +57,6 @@ const PARSED = [
         foundElems: 0,
         original: "-> <P>",
         returned: [],
-        typeFilter: -1,
         userQuery: "-> <p>",
         error: "Found generics without a path",
     },
@@ -66,7 +65,6 @@ const PARSED = [
         foundElems: 0,
         original: "a<\"P\">",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<\"p\">",
         error: "Unexpected `\"` in generics",
     },
@@ -75,7 +73,6 @@ const PARSED = [
         foundElems: 0,
         original: "\"P\" \"P\"",
         returned: [],
-        typeFilter: -1,
         userQuery: "\"p\" \"p\"",
         error: "Cannot have more than one literal search element",
     },
@@ -84,7 +81,6 @@ const PARSED = [
         foundElems: 0,
         original: "P \"P\"",
         returned: [],
-        typeFilter: -1,
         userQuery: "p \"p\"",
         error: "Cannot use literal search when there is more than one element",
     },
@@ -93,7 +89,6 @@ const PARSED = [
         foundElems: 0,
         original: "\"p\" p",
         returned: [],
-        typeFilter: -1,
         userQuery: "\"p\" p",
         error: "You cannot have more than one element if you use quotes",
     },
@@ -102,7 +97,6 @@ const PARSED = [
         foundElems: 0,
         original: "\"const\": p",
         returned: [],
-        typeFilter: -1,
         userQuery: "\"const\": p",
         error: "You cannot use quotes on type filter",
     },
@@ -111,16 +105,14 @@ const PARSED = [
         foundElems: 0,
         original: "a<:a>",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<:a>",
-        error: "Unexpected `:` after `<`",
+        error: "Expected type filter before `:`",
     },
     {
         elems: [],
         foundElems: 0,
         original: "a<::a>",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<::a>",
         error: "Unexpected `::`: paths cannot start with `::`",
     },
@@ -129,7 +121,6 @@ const PARSED = [
         foundElems: 0,
         original: "((a))",
         returned: [],
-        typeFilter: -1,
         userQuery: "((a))",
         error: "Unexpected `(`",
     },
@@ -138,7 +129,6 @@ const PARSED = [
         foundElems: 0,
         original: "(p -> p",
         returned: [],
-        typeFilter: -1,
         userQuery: "(p -> p",
         error: "Unexpected `(`",
     },
@@ -147,7 +137,6 @@ const PARSED = [
         foundElems: 0,
         original: "::a::b",
         returned: [],
-        typeFilter: -1,
         userQuery: "::a::b",
         error: "Paths cannot start with `::`",
     },
@@ -156,7 +145,6 @@ const PARSED = [
         foundElems: 0,
         original: "a::::b",
         returned: [],
-        typeFilter: -1,
         userQuery: "a::::b",
         error: "Unexpected `::::`",
     },
@@ -165,7 +153,6 @@ const PARSED = [
         foundElems: 0,
         original: "a::b::",
         returned: [],
-        typeFilter: -1,
         userQuery: "a::b::",
         error: "Paths cannot end with `::`",
     },
@@ -174,7 +161,6 @@ const PARSED = [
         foundElems: 0,
         original: ":a",
         returned: [],
-        typeFilter: -1,
         userQuery: ":a",
         error: "Expected type filter before `:`",
     },
@@ -183,16 +169,14 @@ const PARSED = [
         foundElems: 0,
         original: "a b:",
         returned: [],
-        typeFilter: -1,
         userQuery: "a b:",
-        error: "Unexpected `:`",
+        error: "Unexpected `:` (expected path after type filter)",
     },
     {
         elems: [],
         foundElems: 0,
         original: "a (b:",
         returned: [],
-        typeFilter: -1,
         userQuery: "a (b:",
         error: "Unexpected `(`",
     },
@@ -201,8 +185,15 @@ const PARSED = [
         foundElems: 0,
         original: "_:",
         returned: [],
-        typeFilter: -1,
         userQuery: "_:",
+        error: "Unexpected `:` (expected path after type filter)",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "_:a",
+        returned: [],
+        userQuery: "_:a",
         error: "Unknown type filter `_`",
     },
     {
@@ -210,7 +201,6 @@ const PARSED = [
         foundElems: 0,
         original: "a-bb",
         returned: [],
-        typeFilter: -1,
         userQuery: "a-bb",
         error: "Unexpected `-` (did you mean `->`?)",
     },
@@ -219,7 +209,6 @@ const PARSED = [
         foundElems: 0,
         original: "a>bb",
         returned: [],
-        typeFilter: -1,
         userQuery: "a>bb",
         error: "Unexpected `>` (did you mean `->`?)",
     },
@@ -228,7 +217,6 @@ const PARSED = [
         foundElems: 0,
         original: "ab'",
         returned: [],
-        typeFilter: -1,
         userQuery: "ab'",
         error: "Unexpected `'`",
     },
@@ -237,7 +225,6 @@ const PARSED = [
         foundElems: 0,
         original: "a->",
         returned: [],
-        typeFilter: -1,
         userQuery: "a->",
         error: "Expected at least one item after `->`",
     },
@@ -246,7 +233,6 @@ const PARSED = [
         foundElems: 0,
         original: '"p" <a>',
         returned: [],
-        typeFilter: -1,
         userQuery: '"p" <a>',
         error: "Found generics without a path",
     },
@@ -255,7 +241,6 @@ const PARSED = [
         foundElems: 0,
         original: '"p" a<a>',
         returned: [],
-        typeFilter: -1,
         userQuery: '"p" a<a>',
         error: "You cannot have more than one element if you use quotes",
     },
@@ -264,7 +249,6 @@ const PARSED = [
         foundElems: 0,
         original: 'a,<',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a,<',
         error: 'Found generics without a path',
     },
@@ -273,7 +257,6 @@ const PARSED = [
         foundElems: 0,
         original: 'aaaaa<>b',
         returned: [],
-        typeFilter: -1,
         userQuery: 'aaaaa<>b',
         error: 'Expected `,`, ` `, `:` or `->`, found `b`',
     },
@@ -282,16 +265,14 @@ const PARSED = [
         foundElems: 0,
         original: 'fn:aaaaa<>b',
         returned: [],
-        typeFilter: -1,
         userQuery: 'fn:aaaaa<>b',
-        error: 'Expected `,`, ` ` or `->`, found `b`',
+        error: 'Expected `,`, ` `, `:` or `->`, found `b`',
     },
     {
         elems: [],
         foundElems: 0,
         original: '->a<>b',
         returned: [],
-        typeFilter: -1,
         userQuery: '->a<>b',
         error: 'Expected `,` or ` `, found `b`',
     },
@@ -300,7 +281,6 @@ const PARSED = [
         foundElems: 0,
         original: 'a<->',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a<->',
         error: 'Unexpected `-` after `<`',
     },
@@ -309,7 +289,6 @@ const PARSED = [
         foundElems: 0,
         original: 'a:: a',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a:: a',
         error: 'Paths cannot end with `::`',
     },
@@ -318,7 +297,6 @@ const PARSED = [
         foundElems: 0,
         original: 'a ::a',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a ::a',
         error: 'Paths cannot start with `::`',
     },
@@ -327,16 +305,14 @@ const PARSED = [
         foundElems: 0,
         original: "a<a>:",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<a>:",
-        error: 'Unexpected `:`',
+        error: 'Unexpected `<` in type filter',
     },
     {
         elems: [],
         foundElems: 0,
         original: "a<>:",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<>:",
         error: 'Unexpected `<` in type filter',
     },
@@ -345,7 +321,6 @@ const PARSED = [
         foundElems: 0,
         original: "a,:",
         returned: [],
-        typeFilter: -1,
         userQuery: "a,:",
         error: 'Unexpected `,` in type filter',
     },
@@ -354,7 +329,6 @@ const PARSED = [
         foundElems: 0,
         original: "a<>  :",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<>  :",
         error: 'Unexpected `<` in type filter',
     },
@@ -363,7 +337,6 @@ const PARSED = [
         foundElems: 0,
         original: "mod : :",
         returned: [],
-        typeFilter: -1,
         userQuery: "mod : :",
         error: 'Unexpected `:`',
     },
@@ -372,7 +345,6 @@ const PARSED = [
         foundElems: 0,
         original: "a!a",
         returned: [],
-        typeFilter: -1,
         userQuery: "a!a",
         error: 'Unexpected `!`: it can only be at the end of an ident',
     },
@@ -381,7 +353,6 @@ const PARSED = [
         foundElems: 0,
         original: "a!!",
         returned: [],
-        typeFilter: -1,
         userQuery: "a!!",
         error: 'Cannot have more than one `!` in an ident',
     },
@@ -390,7 +361,6 @@ const PARSED = [
         foundElems: 0,
         original: "mod:a!",
         returned: [],
-        typeFilter: -1,
         userQuery: "mod:a!",
         error: 'Invalid search type: macro `!` and `mod` both specified',
     },
@@ -399,7 +369,6 @@ const PARSED = [
         foundElems: 0,
         original: "a!::a",
         returned: [],
-        typeFilter: -1,
         userQuery: "a!::a",
         error: 'Cannot have associated items in macros',
     },
@@ -408,7 +377,6 @@ const PARSED = [
         foundElems: 0,
         original: "a<",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<",
         error: "Unclosed `<`",
     },
diff --git a/tests/rustdoc-js-std/parser-filter.js b/tests/rustdoc-js-std/parser-filter.js
index 01f65b478f8..e23447ab75d 100644
--- a/tests/rustdoc-js-std/parser-filter.js
+++ b/tests/rustdoc-js-std/parser-filter.js
@@ -1,4 +1,14 @@
-const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo', 'macro!', 'macro:mac!', 'a::mac!'];
+const QUERY = [
+    'fn:foo',
+    'enum : foo',
+    'macro<f>:foo',
+    'macro!',
+    'macro:mac!',
+    'a::mac!',
+    '-> fn:foo',
+    '-> fn:foo<fn:bar>',
+    '-> fn:foo<fn:bar, enum : baz::fuzz>',
+];
 
 const PARSED = [
     {
@@ -8,11 +18,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "foo",
             generics: [],
+            typeFilter: 5,
         }],
         foundElems: 1,
         original: "fn:foo",
         returned: [],
-        typeFilter: 5,
         userQuery: "fn:foo",
         error: null,
     },
@@ -23,11 +33,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "foo",
             generics: [],
+            typeFilter: 4,
         }],
         foundElems: 1,
         original: "enum : foo",
         returned: [],
-        typeFilter: 4,
         userQuery: "enum : foo",
         error: null,
     },
@@ -36,9 +46,8 @@ const PARSED = [
         foundElems: 0,
         original: "macro<f>:foo",
         returned: [],
-        typeFilter: -1,
         userQuery: "macro<f>:foo",
-        error: "Unexpected `:`",
+        error: "Unexpected `<` in type filter",
     },
     {
         elems: [{
@@ -47,11 +56,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "macro",
             generics: [],
+            typeFilter: 14,
         }],
         foundElems: 1,
         original: "macro!",
         returned: [],
-        typeFilter: 14,
         userQuery: "macro!",
         error: null,
     },
@@ -62,11 +71,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "mac",
             generics: [],
+            typeFilter: 14,
         }],
         foundElems: 1,
         original: "macro:mac!",
         returned: [],
-        typeFilter: 14,
         userQuery: "macro:mac!",
         error: null,
     },
@@ -77,12 +86,83 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "mac",
             generics: [],
+            typeFilter: 14,
         }],
         foundElems: 1,
         original: "a::mac!",
         returned: [],
-        typeFilter: 14,
         userQuery: "a::mac!",
         error: null,
     },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> fn:foo",
+        returned: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [],
+            typeFilter: 5,
+        }],
+        userQuery: "-> fn:foo",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> fn:foo<fn:bar>",
+        returned: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [
+                {
+                    name: "bar",
+                    fullPath: ["bar"],
+                    pathWithoutLast: [],
+                    pathLast: "bar",
+                    generics: [],
+                    typeFilter: 5,
+                }
+            ],
+            typeFilter: 5,
+        }],
+        userQuery: "-> fn:foo<fn:bar>",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> fn:foo<fn:bar, enum : baz::fuzz>",
+        returned: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [
+                {
+                    name: "bar",
+                    fullPath: ["bar"],
+                    pathWithoutLast: [],
+                    pathLast: "bar",
+                    generics: [],
+                    typeFilter: 5,
+                },
+                {
+                    name: "baz::fuzz",
+                    fullPath: ["baz", "fuzz"],
+                    pathWithoutLast: ["baz"],
+                    pathLast: "fuzz",
+                    generics: [],
+                    typeFilter: 4,
+                },
+            ],
+            typeFilter: 5,
+        }],
+        userQuery: "-> fn:foo<fn:bar, enum : baz::fuzz>",
+        error: null,
+    },
 ];
diff --git a/tests/rustdoc-js-std/parser-generics.js b/tests/rustdoc-js-std/parser-generics.js
index 0cf7f5019aa..c448d845acb 100644
--- a/tests/rustdoc-js-std/parser-generics.js
+++ b/tests/rustdoc-js-std/parser-generics.js
@@ -6,7 +6,6 @@ const PARSED = [
         foundElems: 0,
         original: 'A<B<C<D>,  E>',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a<b<c<d>,  e>',
         error: 'Unexpected `<` after `<`',
     },
@@ -18,6 +17,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "p",
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: "u8",
@@ -25,12 +25,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "p<> u8",
         returned: [],
-        typeFilter: -1,
         userQuery: "p<> u8",
         error: null,
     },
@@ -50,12 +50,12 @@ const PARSED = [
                         generics: [],
                     },
                 ],
+                typeFilter: -1,
             },
         ],
         foundElems: 1,
         original: '"p"<a>',
         returned: [],
-        typeFilter: -1,
         userQuery: '"p"<a>',
         error: null,
     },
diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js
index 6c17d00f16e..be42b7aa463 100644
--- a/tests/rustdoc-js-std/parser-ident.js
+++ b/tests/rustdoc-js-std/parser-ident.js
@@ -23,11 +23,11 @@ const PARSED = [
                     generics: [],
                 },
             ],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: "R<!>",
         returned: [],
-        typeFilter: -1,
         userQuery: "r<!>",
         error: null,
     },
@@ -38,11 +38,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "!",
             generics: [],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: "!",
         returned: [],
-        typeFilter: -1,
         userQuery: "!",
         error: null,
     },
@@ -53,11 +53,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
+            typeFilter: 14,
         }],
         foundElems: 1,
         original: "a!",
         returned: [],
-        typeFilter: 14,
         userQuery: "a!",
         error: null,
     },
@@ -66,7 +66,6 @@ const PARSED = [
         foundElems: 0,
         original: "a!::b",
         returned: [],
-        typeFilter: -1,
         userQuery: "a!::b",
         error: "Cannot have associated items in macros",
     },
@@ -77,11 +76,11 @@ const PARSED = [
             pathWithoutLast: ["!"],
             pathLast: "b",
             generics: [],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: "!::b",
         returned: [],
-        typeFilter: -1,
         userQuery: "!::b",
         error: null,
     },
@@ -90,7 +89,6 @@ const PARSED = [
         foundElems: 0,
         original: "a!::b!",
         returned: [],
-        typeFilter: -1,
         userQuery: "a!::b!",
         error: "Cannot have associated items in macros",
     },
diff --git a/tests/rustdoc-js-std/parser-literal.js b/tests/rustdoc-js-std/parser-literal.js
index 87b3baff1e2..3a31d1bddff 100644
--- a/tests/rustdoc-js-std/parser-literal.js
+++ b/tests/rustdoc-js-std/parser-literal.js
@@ -16,11 +16,11 @@ const PARSED = [
                     generics: [],
                 },
             ],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: "R<P>",
         returned: [],
-        typeFilter: -1,
         userQuery: "r<p>",
         error: null,
     }
diff --git a/tests/rustdoc-js-std/parser-paths.js b/tests/rustdoc-js-std/parser-paths.js
index 9f823f9336a..f3e421f5ffa 100644
--- a/tests/rustdoc-js-std/parser-paths.js
+++ b/tests/rustdoc-js-std/parser-paths.js
@@ -8,11 +8,11 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "b",
             generics: [],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: "A::B",
         returned: [],
-        typeFilter: -1,
         userQuery: "a::b",
         error: null,
     },
@@ -24,6 +24,7 @@ const PARSED = [
                 pathWithoutLast: ["a"],
                 pathLast: "b",
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: "c",
@@ -31,12 +32,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "c",
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: 'A::B,C',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a::b,c',
         error: null,
     },
@@ -56,6 +57,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
+                typeFilter: -1,
             },
             {
                 name: "c",
@@ -63,12 +65,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "c",
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: 'A::B<f>,C',
         returned: [],
-        typeFilter: -1,
         userQuery: 'a::b<f>,c',
         error: null,
     },
@@ -79,11 +81,11 @@ const PARSED = [
             pathWithoutLast: ["mod"],
             pathLast: "a",
             generics: [],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: "mod::a",
         returned: [],
-        typeFilter: -1,
         userQuery: "mod::a",
         error: null,
     },
diff --git a/tests/rustdoc-js-std/parser-quote.js b/tests/rustdoc-js-std/parser-quote.js
index 1e16c90de5e..d5d67cac892 100644
--- a/tests/rustdoc-js-std/parser-quote.js
+++ b/tests/rustdoc-js-std/parser-quote.js
@@ -19,8 +19,8 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "p",
             generics: [],
+            typeFilter: -1,
         }],
-        typeFilter: -1,
         userQuery: '-> "p"',
         error: null,
     },
@@ -31,11 +31,11 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "p",
             generics: [],
+            typeFilter: -1,
         }],
         foundElems: 1,
         original: '"p",',
         returned: [],
-        typeFilter: -1,
         userQuery: '"p",',
         error: null,
     },
@@ -44,7 +44,6 @@ const PARSED = [
         foundElems: 0,
         original: '"p" -> a',
         returned: [],
-        typeFilter: -1,
         userQuery: '"p" -> a',
         error: "You cannot have more than one element if you use quotes",
     },
@@ -53,7 +52,6 @@ const PARSED = [
         foundElems: 0,
         original: '"a" -> "p"',
         returned: [],
-        typeFilter: -1,
         userQuery: '"a" -> "p"',
         error: "Cannot have more than one literal search element",
     },
@@ -62,7 +60,6 @@ const PARSED = [
         foundElems: 0,
         original: '->"-"',
         returned: [],
-        typeFilter: -1,
         userQuery: '->"-"',
         error: 'Unexpected `-` in a string element',
     },
@@ -71,7 +68,6 @@ const PARSED = [
         foundElems: 0,
         original: '"a',
         returned: [],
-        typeFilter: -1,
         userQuery: '"a',
         error: 'Unclosed `"`',
     },
@@ -80,7 +76,6 @@ const PARSED = [
         foundElems: 0,
         original: '""',
         returned: [],
-        typeFilter: -1,
         userQuery: '""',
         error: 'Cannot have empty string element',
     },
diff --git a/tests/rustdoc-js-std/parser-returned.js b/tests/rustdoc-js-std/parser-returned.js
index 6fce17dcabd..c2981319055 100644
--- a/tests/rustdoc-js-std/parser-returned.js
+++ b/tests/rustdoc-js-std/parser-returned.js
@@ -25,8 +25,8 @@ const PARSED = [
                     generics: [],
                 },
             ],
+            typeFilter: -1,
         }],
-        typeFilter: -1,
         userQuery: "-> f<p>",
         error: null,
     },
@@ -40,8 +40,8 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "p",
             generics: [],
+            typeFilter: -1,
         }],
-        typeFilter: -1,
         userQuery: "-> p",
         error: null,
     },
@@ -55,8 +55,8 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
+            typeFilter: -1,
         }],
-        typeFilter: -1,
         userQuery: "->,a",
         error: null,
     },
@@ -67,6 +67,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "aaaaa",
             generics: [],
+            typeFilter: -1,
         }],
         foundElems: 2,
         original: "aaaaa->a",
@@ -76,8 +77,8 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
+            typeFilter: -1,
         }],
-        typeFilter: -1,
         userQuery: "aaaaa->a",
         error: null,
     },
@@ -91,8 +92,8 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "!",
             generics: [],
+            typeFilter: -1,
         }],
-        typeFilter: -1,
         userQuery: "-> !",
         error: null,
     },
diff --git a/tests/rustdoc-js-std/parser-separators.js b/tests/rustdoc-js-std/parser-separators.js
index 5b7abdfa8d6..fc8c5114c4e 100644
--- a/tests/rustdoc-js-std/parser-separators.js
+++ b/tests/rustdoc-js-std/parser-separators.js
@@ -19,6 +19,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'aaaaaa',
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: 'b',
@@ -26,12 +27,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'b',
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "aaaaaa	b",
         returned: [],
-        typeFilter: -1,
         userQuery: "aaaaaa	b",
         error: null,
     },
@@ -43,6 +44,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'a',
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: 'b',
@@ -50,12 +52,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'b',
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "a b",
         returned: [],
-        typeFilter: -1,
         userQuery: "a b",
         error: null,
     },
@@ -67,6 +69,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'a',
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: 'b',
@@ -74,12 +77,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'b',
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "a,b",
         returned: [],
-        typeFilter: -1,
         userQuery: "a,b",
         error: null,
     },
@@ -91,6 +94,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'a',
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: 'b',
@@ -98,12 +102,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'b',
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "a\tb",
         returned: [],
-        typeFilter: -1,
         userQuery: "a\tb",
         error: null,
     },
@@ -130,12 +134,12 @@ const PARSED = [
                         generics: [],
                     },
                 ],
+                typeFilter: -1,
             },
         ],
         foundElems: 1,
         original: "a<b c>",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<b c>",
         error: null,
     },
@@ -162,12 +166,12 @@ const PARSED = [
                         generics: [],
                     },
                 ],
+                typeFilter: -1,
             },
         ],
         foundElems: 1,
         original: "a<b,c>",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<b,c>",
         error: null,
     },
@@ -194,12 +198,12 @@ const PARSED = [
                         generics: [],
                     },
                 ],
+                typeFilter: -1,
             },
         ],
         foundElems: 1,
         original: "a<b\tc>",
         returned: [],
-        typeFilter: -1,
         userQuery: "a<b\tc>",
         error: null,
     },
diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js
index a3d85aeca5e..dc1049a70bc 100644
--- a/tests/rustdoc-js-std/parser-weird-queries.js
+++ b/tests/rustdoc-js-std/parser-weird-queries.js
@@ -20,6 +20,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "a",
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: "b",
@@ -27,12 +28,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "b",
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "a b",
         returned: [],
-        typeFilter: -1,
         userQuery: "a b",
         error: null,
     },
@@ -44,6 +45,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "a",
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: "b",
@@ -51,12 +53,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "b",
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "a   b",
         returned: [],
-        typeFilter: -1,
         userQuery: "a   b",
         error: null,
     },
@@ -65,7 +67,6 @@ const PARSED = [
         foundElems: 0,
         original: "a,b(c)",
         returned: [],
-        typeFilter: -1,
         userQuery: "a,b(c)",
         error: "Unexpected `(`",
     },
@@ -77,6 +78,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "aaa",
                 generics: [],
+                typeFilter: -1,
             },
             {
                 name: "a",
@@ -84,12 +86,12 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "a",
                 generics: [],
+                typeFilter: -1,
             },
         ],
         foundElems: 2,
         original: "aaa,a",
         returned: [],
-        typeFilter: -1,
         userQuery: "aaa,a",
         error: null,
     },
@@ -98,7 +100,6 @@ const PARSED = [
         foundElems: 0,
         original: ",,,,",
         returned: [],
-        typeFilter: -1,
         userQuery: ",,,,",
         error: null,
     },
@@ -107,17 +108,15 @@ const PARSED = [
         foundElems: 0,
         original: 'mod    :',
         returned: [],
-        typeFilter: 0,
         userQuery: 'mod    :',
-        error: null,
+        error: "Unexpected `:` (expected path after type filter)",
     },
     {
         elems: [],
         foundElems: 0,
         original: 'mod\t:',
         returned: [],
-        typeFilter: 0,
         userQuery: 'mod\t:',
-        error: null,
+        error: "Unexpected `:` (expected path after type filter)",
     },
 ];
diff --git a/tests/rustdoc-js/generics-impl.js b/tests/rustdoc-js/generics-impl.js
index bb6e0041db5..5051743bda2 100644
--- a/tests/rustdoc-js/generics-impl.js
+++ b/tests/rustdoc-js/generics-impl.js
@@ -5,6 +5,8 @@ const QUERY = [
     'Aaaaaaa -> bool',
     'Aaaaaaa -> usize',
     'Read -> u64',
+    'trait:Read -> u64',
+    'struct:Read -> u64',
     'bool -> u64',
     'Ddddddd -> u64',
     '-> Ddddddd'
@@ -37,6 +39,17 @@ const EXPECTED = [
         ],
     },
     {
+        // trait:Read -> u64
+        'others': [
+            { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
+            { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
+        ],
+    },
+    {
+        // struct:Read -> u64
+        'others': [],
+    },
+    {
         // bool -> u64
         'others': [
             { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' },
diff --git a/tests/rustdoc-js/generics.js b/tests/rustdoc-js/generics.js
index 5e5ba7cd9ac..f79c709ad6c 100644
--- a/tests/rustdoc-js/generics.js
+++ b/tests/rustdoc-js/generics.js
@@ -2,6 +2,8 @@
 
 const QUERY = [
     'R<P>',
+    'R<struct:P>',
+    'R<enum:P>',
     '"P"',
     'P',
     'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
@@ -21,6 +23,20 @@ const EXPECTED = [
         ],
     },
     {
+        // R<struct:P>
+        'returned': [
+            { 'path': 'generics', 'name': 'alef' },
+        ],
+        'in_args': [
+            { 'path': 'generics', 'name': 'alpha' },
+        ],
+    },
+    {
+        // R<enum:P>
+        'returned': [],
+        'in_args': [],
+    },
+    {
         // "P"
         'others': [
             { 'path': 'generics', 'name': 'P' },
diff --git a/tests/rustdoc-js/primitive.js b/tests/rustdoc-js/primitive.js
index 918f7099918..4aec98c3403 100644
--- a/tests/rustdoc-js/primitive.js
+++ b/tests/rustdoc-js/primitive.js
@@ -3,6 +3,8 @@
 const QUERY = [
     "i32",
     "str",
+    "primitive:str",
+    "struct:str",
     "TotoIsSomewhere",
 ];
 
@@ -18,6 +20,14 @@ const EXPECTED = [
         ],
     },
     {
+        'returned': [
+            { 'path': 'primitive', 'name': 'foo' },
+        ],
+    },
+    {
+        'returned': [],
+    },
+    {
         'others': [],
         'in_args': [],
         'returned': [],
diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout
index 5ad38e4fd98..72f5f933d8d 100644
--- a/tests/rustdoc-ui/z-help.stdout
+++ b/tests/rustdoc-ui/z-help.stdout
@@ -183,6 +183,7 @@
     -Z                               threads=val -- use a thread pool with N threads
     -Z                      time-llvm-passes=val -- measure time of each LLVM pass (default: no)
     -Z                           time-passes=val -- measure time of each rustc pass (default: no)
+    -Z                    time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`)
     -Z                 tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
     -Z                             tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
     -Z                          trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs
new file mode 100644
index 00000000000..3c011d72b02
--- /dev/null
+++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs
@@ -0,0 +1,6 @@
+// It is unclear whether a fully unconfigured crate should link to standard library,
+// or what its `no_std`/`no_core`/`compiler_builtins` status, more precisely.
+// Currently the usual standard library prelude is added to such crates,
+// and therefore they link to libstd.
+
+#![cfg(FALSE)]
diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs
new file mode 100644
index 00000000000..21ea3ec79b4
--- /dev/null
+++ b/tests/ui/cfg/cfg-false-feature.rs
@@ -0,0 +1,20 @@
+// It is unclear which features should be in effect in a fully unconfigured crate (issue #104633).
+// Currently none on the features are in effect, so we get the feature gates reported.
+
+// check-pass
+// compile-flags: --crate-type lib
+
+#![feature(decl_macro)]
+#![cfg(FALSE)]
+#![feature(box_syntax)]
+
+macro mac() {} //~ WARN `macro` is experimental
+               //~| WARN unstable syntax can change at any point in the future
+
+trait A = Clone; //~ WARN trait aliases are experimental
+                 //~| WARN unstable syntax can change at any point in the future
+
+fn main() {
+    let box _ = Box::new(0); //~ WARN box pattern syntax is experimental
+                             //~| WARN unstable syntax can change at any point in the future
+}
diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr
new file mode 100644
index 00000000000..14673fbdb14
--- /dev/null
+++ b/tests/ui/cfg/cfg-false-feature.stderr
@@ -0,0 +1,35 @@
+warning: trait aliases are experimental
+  --> $DIR/cfg-false-feature.rs:14:1
+   |
+LL | trait A = Clone;
+   | ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
+   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
+   = warning: unstable syntax can change at any point in the future, causing a hard error!
+   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: `macro` is experimental
+  --> $DIR/cfg-false-feature.rs:11:1
+   |
+LL | macro mac() {}
+   | ^^^^^^^^^^^^^^
+   |
+   = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
+   = help: add `#![feature(decl_macro)]` to the crate attributes to enable
+   = warning: unstable syntax can change at any point in the future, causing a hard error!
+   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: box pattern syntax is experimental
+  --> $DIR/cfg-false-feature.rs:18:9
+   |
+LL |     let box _ = Box::new(0);
+   |         ^^^^^
+   |
+   = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+   = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+   = warning: unstable syntax can change at any point in the future, causing a hard error!
+   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/cfg/cfg_false_no_std.rs b/tests/ui/cfg/cfg_false_no_std.rs
new file mode 100644
index 00000000000..319ea078187
--- /dev/null
+++ b/tests/ui/cfg/cfg_false_no_std.rs
@@ -0,0 +1,11 @@
+// Currently no error because the panic handler is supplied by libstd linked though the empty
+// library, but the desirable behavior is unclear (see comments in cfg_false_lib.rs).
+
+// check-pass
+// aux-build: cfg_false_lib.rs
+
+#![no_std]
+
+extern crate cfg_false_lib as _;
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr
index 7b4d46b8209..6b3396a25cf 100644
--- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr
@@ -1,8 +1,8 @@
 error: unconstrained generic constant
-  --> $DIR/cross_crate_predicate.rs:7:13
+  --> $DIR/cross_crate_predicate.rs:7:44
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                            ^
    |
    = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
 note: required by a bound in `test1`
@@ -12,10 +12,10 @@ LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
 
 error: unconstrained generic constant
-  --> $DIR/cross_crate_predicate.rs:7:13
+  --> $DIR/cross_crate_predicate.rs:7:44
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                            ^
    |
    = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
 note: required by a bound in `test1`
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
new file mode 100644
index 00000000000..64317b9d39a
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
@@ -0,0 +1,52 @@
+// check-pass
+// known-bug: #97156
+
+#![feature(const_type_id, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+use std::any::TypeId;
+// `One` and `Two` are currently considered equal types, as both
+// `One <: Two` and `One :> Two` holds.
+type One = for<'a> fn(&'a (), &'a ());
+type Two = for<'a, 'b> fn(&'a (), &'b ());
+trait AssocCt {
+    const ASSOC: usize;
+}
+const fn to_usize<T: 'static>() -> usize {
+    const WHAT_A_TYPE: TypeId = TypeId::of::<One>();
+    match TypeId::of::<T>() {
+        WHAT_A_TYPE => 0,
+        _ => 1000,
+    } 
+}
+impl<T: 'static> AssocCt for T {
+    const ASSOC: usize = to_usize::<T>();
+}
+
+trait WithAssoc<U> {
+    type Assoc;
+}
+impl<T: 'static> WithAssoc<()> for T where [(); <T as AssocCt>::ASSOC]: {
+    type Assoc = [u8; <T as AssocCt>::ASSOC];
+}
+
+fn generic<T: 'static, U>(x: <T as WithAssoc<U>>::Assoc) -> <T as WithAssoc<U>>::Assoc
+where
+    [(); <T as AssocCt>::ASSOC]:,
+    T: WithAssoc<U>,
+{
+    x
+}
+
+
+fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc
+where
+    One: WithAssoc<T>,
+{
+    let x: <Two as WithAssoc<T>>::Assoc = generic::<One, T>(x);
+    x
+}
+
+fn main() {
+    println!("{:?}", unsound::<()>([]));
+}
diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr
index 6d8955e411e..394dd44d40d 100644
--- a/tests/ui/const-generics/type_mismatch.stderr
+++ b/tests/ui/const-generics/type_mismatch.stderr
@@ -1,8 +1,8 @@
 error: the constant `N` is not of type `u8`
-  --> $DIR/type_mismatch.rs:2:5
+  --> $DIR/type_mismatch.rs:2:11
    |
 LL |     bar::<N>()
-   |     ^^^^^^^^
+   |           ^ expected `u8`, found `usize`
    |
 note: required by a bound in `bar`
   --> $DIR/type_mismatch.rs:6:8
diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs
index 28edf514402..1abe708d19e 100644
--- a/tests/ui/consts/const-eval/panic-assoc-never-type.rs
+++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -11,5 +11,5 @@ impl PrintName {
 }
 
 fn main() {
-    let _ = PrintName::VOID; //~ constant
+    let _ = PrintName::VOID; //~ erroneous constant used
 }
diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.rs b/tests/ui/consts/const-eval/transmute-size-mismatch.rs
new file mode 100644
index 00000000000..2410baea28c
--- /dev/null
+++ b/tests/ui/consts/const-eval/transmute-size-mismatch.rs
@@ -0,0 +1,24 @@
+#![feature(core_intrinsics)]
+#![feature(custom_mir)]
+
+// These cases are statically rejected by `mem::transmute`, so we need custom
+// MIR to be able to get to constant evaluation.
+use std::intrinsics::mir::*;
+
+#[custom_mir(dialect = "runtime", phase = "initial")]
+const unsafe fn mir_transmute<T, U>(x: T) -> U {
+    mir!{
+        {
+            RET = CastTransmute(x);
+            //~^ ERROR evaluation of constant value failed
+            //~| ERROR evaluation of constant value failed
+            Return()
+        }
+    }
+}
+
+const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) };
+
+const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) };
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr
new file mode 100644
index 00000000000..e051491d343
--- /dev/null
+++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr
@@ -0,0 +1,37 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/transmute-size-mismatch.rs:12:13
+   |
+LL |             RET = CastTransmute(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 4-byte type to 2-byte type: `i32` -> `u16`
+   |
+note: inside `mir_transmute::<i32, u16>`
+  --> $DIR/transmute-size-mismatch.rs:12:13
+   |
+LL |             RET = CastTransmute(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+note: inside `FROM_BIGGER`
+  --> $DIR/transmute-size-mismatch.rs:20:35
+   |
+LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/transmute-size-mismatch.rs:12:13
+   |
+LL |             RET = CastTransmute(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 2-byte type to 4-byte type: `i16` -> `u32`
+   |
+note: inside `mir_transmute::<i16, u32>`
+  --> $DIR/transmute-size-mismatch.rs:12:13
+   |
+LL |             RET = CastTransmute(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+note: inside `FROM_SMALLER`
+  --> $DIR/transmute-size-mismatch.rs:22:36
+   |
+LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr
index 2d86bd88f1c..3ad1ac974c8 100644
--- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr
@@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:96:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr
index a89d7ec5f6d..a66706d1af9 100644
--- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr
@@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:96:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
index 231005d7e39..74bc6317c80 100644
--- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
+++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
@@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/validate_uninhabited_zsts.rs:4:14
    |
 LL |     unsafe { std::mem::transmute(()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!`
    |
 note: inside `foo`
   --> $DIR/validate_uninhabited_zsts.rs:4:14
diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
index 231005d7e39..74bc6317c80 100644
--- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
+++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
@@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/validate_uninhabited_zsts.rs:4:14
    |
 LL |     unsafe { std::mem::transmute(()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!`
    |
 note: inside `foo`
   --> $DIR/validate_uninhabited_zsts.rs:4:14
diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.stderr b/tests/ui/feature-gates/feature-gate-link_cfg.stderr
index 8f47d596521..97b6cbca412 100644
--- a/tests/ui/feature-gates/feature-gate-link_cfg.stderr
+++ b/tests/ui/feature-gates/feature-gate-link_cfg.stderr
@@ -4,7 +4,6 @@ error[E0658]: link cfg is unstable
 LL | #[link(name = "foo", cfg(foo))]
    |                      ^^^^^^^^
    |
-   = note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information
    = help: add `#![feature(link_cfg)]` to the crate attributes to enable
 
 error: aborting due to previous error
diff --git a/tests/ui/impl-trait/nested-return-type2.rs b/tests/ui/impl-trait/nested-return-type2.rs
index fe883ce6fc8..e1d5511379e 100644
--- a/tests/ui/impl-trait/nested-return-type2.rs
+++ b/tests/ui/impl-trait/nested-return-type2.rs
@@ -26,7 +26,6 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
 // Lazy TAIT would error out, but we inserted a hack to make it work again,
 // keeping backwards compatibility.
 fn foo() -> impl Trait<Assoc = impl Send> {
-    //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
     || 42
 }
 
diff --git a/tests/ui/impl-trait/nested-return-type2.stderr b/tests/ui/impl-trait/nested-return-type2.stderr
deleted file mode 100644
index 09ad3bd05c1..00000000000
--- a/tests/ui/impl-trait/nested-return-type2.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
-  --> $DIR/nested-return-type2.rs:28:24
-   |
-LL |     type Assoc: Duh;
-   |                 --- this associated type bound is unsatisfied for `impl Send`
-...
-LL | fn foo() -> impl Trait<Assoc = impl Send> {
-   |                        ^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
-help: add this bound
-   |
-LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
-   |                                          +++++
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/impl-trait/nested-return-type3.rs b/tests/ui/impl-trait/nested-return-type3.rs
index 5a764fc4c28..74b4dae22eb 100644
--- a/tests/ui/impl-trait/nested-return-type3.rs
+++ b/tests/ui/impl-trait/nested-return-type3.rs
@@ -13,7 +13,6 @@ impl<F: Duh> Trait for F {
 }
 
 fn foo() -> impl Trait<Assoc = impl Send> {
-    //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
     42
 }
 
diff --git a/tests/ui/impl-trait/nested-return-type3.stderr b/tests/ui/impl-trait/nested-return-type3.stderr
deleted file mode 100644
index 632de71aa4c..00000000000
--- a/tests/ui/impl-trait/nested-return-type3.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
-  --> $DIR/nested-return-type3.rs:15:24
-   |
-LL |     type Assoc: Duh;
-   |                 --- this associated type bound is unsatisfied for `impl Send`
-...
-LL | fn foo() -> impl Trait<Assoc = impl Send> {
-   |                        ^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
-help: add this bound
-   |
-LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
-   |                                          +++++
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/imports/auxiliary/glob-conflict.rs b/tests/ui/imports/auxiliary/glob-conflict.rs
index c83db64c643..8a146378b43 100644
--- a/tests/ui/imports/auxiliary/glob-conflict.rs
+++ b/tests/ui/imports/auxiliary/glob-conflict.rs
@@ -1,3 +1,5 @@
+#![allow(ambiguous_glob_reexports)]
+
 mod m1 {
     pub fn f() {}
 }
diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed
index 0f688fa2823..0e60c73b67a 100644
--- a/tests/ui/imports/issue-99695-b.fixed
+++ b/tests/ui/imports/issue-99695-b.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
 
     mod p {
diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs
index b433997e53f..031443a1f5d 100644
--- a/tests/ui/imports/issue-99695-b.rs
+++ b/tests/ui/imports/issue-99695-b.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
 
     mod p {
diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed
index 17ff409324e..6bf228b23aa 100644
--- a/tests/ui/imports/issue-99695.fixed
+++ b/tests/ui/imports/issue-99695.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
     #[macro_export]
     macro_rules! nu {
diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs
index b8979bcb734..f7199f1497a 100644
--- a/tests/ui/imports/issue-99695.rs
+++ b/tests/ui/imports/issue-99695.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
+#![allow(unused, nonstandard_style)]
 mod m {
     #[macro_export]
     macro_rules! nu {
diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs
index 29e9b8ec841..ce700ae0de9 100644
--- a/tests/ui/imports/local-modularized-tricky-fail-1.rs
+++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs
@@ -1,4 +1,5 @@
 #![feature(decl_macro)]
+#![allow(ambiguous_glob_reexports)]
 
 macro_rules! define_exported { () => {
     #[macro_export]
diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr
index 20eadaaaa56..52a01e8bcdf 100644
--- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr
+++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr
@@ -1,12 +1,12 @@
 error[E0659]: `exported` is ambiguous
-  --> $DIR/local-modularized-tricky-fail-1.rs:28:1
+  --> $DIR/local-modularized-tricky-fail-1.rs:29:1
    |
 LL | exported!();
    | ^^^^^^^^ ambiguous name
    |
    = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `exported` could refer to the macro defined here
-  --> $DIR/local-modularized-tricky-fail-1.rs:5:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:6:5
    |
 LL | /     macro_rules! exported {
 LL | |         () => ()
@@ -16,7 +16,7 @@ LL | |     }
 LL |       define_exported!();
    |       ------------------ in this macro invocation
 note: `exported` could also refer to the macro imported here
-  --> $DIR/local-modularized-tricky-fail-1.rs:22:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:23:5
    |
 LL | use inner1::*;
    |     ^^^^^^^^^
@@ -24,7 +24,7 @@ LL | use inner1::*;
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0659]: `panic` is ambiguous
-  --> $DIR/local-modularized-tricky-fail-1.rs:35:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:36:5
    |
 LL |     panic!();
    |     ^^^^^ ambiguous name
@@ -32,7 +32,7 @@ LL |     panic!();
    = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `panic` could refer to a macro from prelude
 note: `panic` could also refer to the macro defined here
-  --> $DIR/local-modularized-tricky-fail-1.rs:11:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:12:5
    |
 LL | /     macro_rules! panic {
 LL | |         () => ()
@@ -45,7 +45,7 @@ LL |       define_panic!();
    = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0659]: `include` is ambiguous
-  --> $DIR/local-modularized-tricky-fail-1.rs:46:1
+  --> $DIR/local-modularized-tricky-fail-1.rs:47:1
    |
 LL | include!();
    | ^^^^^^^ ambiguous name
@@ -53,7 +53,7 @@ LL | include!();
    = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `include` could refer to a macro from prelude
 note: `include` could also refer to the macro defined here
-  --> $DIR/local-modularized-tricky-fail-1.rs:17:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:18:5
    |
 LL | /     macro_rules! include {
 LL | |         () => ()
diff --git a/tests/ui/lint/anonymous-reexport.rs b/tests/ui/lint/anonymous-reexport.rs
index 5d56ae6f969..11ac5d07140 100644
--- a/tests/ui/lint/anonymous-reexport.rs
+++ b/tests/ui/lint/anonymous-reexport.rs
@@ -1,4 +1,4 @@
-#![deny(useless_anonymous_reexport)]
+#![deny(unused_imports)]
 #![crate_type = "rlib"]
 
 mod my_mod {
@@ -9,13 +9,11 @@ mod my_mod {
 }
 
 pub use self::my_mod::Foo as _;
-pub use self::my_mod::TyFoo as _;
-pub use self::my_mod::Bar as _; //~ ERROR
-pub use self::my_mod::TyBar as _; //~ ERROR
-pub use self::my_mod::{Bar as _}; //~ ERROR
-pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR
-pub use self::my_mod::{Bar as _, TyBar as _};
-//~^ ERROR
-//~| ERROR
+pub use self::my_mod::TyFoo as _; //~ ERROR unused import
+pub use self::my_mod::Bar as _; //~ ERROR unused import
+pub use self::my_mod::TyBar as _; //~ ERROR unused import
+pub use self::my_mod::{Bar as _}; //~ ERROR unused import
+pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR unused import
+pub use self::my_mod::{Bar as _, TyBar as _}; //~ ERROR unused imports
 #[allow(unused_imports)]
 use self::my_mod::TyBar as _;
diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr
index f4f8b41c417..e3854a5459e 100644
--- a/tests/ui/lint/anonymous-reexport.stderr
+++ b/tests/ui/lint/anonymous-reexport.stderr
@@ -1,55 +1,44 @@
-error: useless anonymous re-export
-  --> $DIR/anonymous-reexport.rs:13:1
+error: unused import: `self::my_mod::TyFoo as _`
+  --> $DIR/anonymous-reexport.rs:12:9
    |
-LL | pub use self::my_mod::Bar as _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub use self::my_mod::TyFoo as _;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
 note: the lint level is defined here
   --> $DIR/anonymous-reexport.rs:1:9
    |
-LL | #![deny(useless_anonymous_reexport)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
 
-error: useless anonymous re-export
-  --> $DIR/anonymous-reexport.rs:14:1
+error: unused import: `self::my_mod::Bar as _`
+  --> $DIR/anonymous-reexport.rs:13:9
    |
-LL | pub use self::my_mod::TyBar as _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub use self::my_mod::Bar as _;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unused import: `self::my_mod::TyBar as _`
+  --> $DIR/anonymous-reexport.rs:14:9
    |
-   = note: only anonymous re-exports of traits are useful, this is a `type alias`
+LL | pub use self::my_mod::TyBar as _;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: useless anonymous re-export
+error: unused import: `Bar as _`
   --> $DIR/anonymous-reexport.rs:15:24
    |
 LL | pub use self::my_mod::{Bar as _};
    |                        ^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
 
-error: useless anonymous re-export
+error: unused import: `Bar as _`
   --> $DIR/anonymous-reexport.rs:16:24
    |
 LL | pub use self::my_mod::{Bar as _, Foo as _};
    |                        ^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
 
-error: useless anonymous re-export
+error: unused imports: `Bar as _`, `TyBar as _`
   --> $DIR/anonymous-reexport.rs:17:24
    |
 LL | pub use self::my_mod::{Bar as _, TyBar as _};
-   |                        ^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `struct`
-
-error: useless anonymous re-export
-  --> $DIR/anonymous-reexport.rs:17:34
-   |
-LL | pub use self::my_mod::{Bar as _, TyBar as _};
-   |                                  ^^^^^^^^^^
-   |
-   = note: only anonymous re-exports of traits are useful, this is a `type alias`
+   |                        ^^^^^^^^  ^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs
new file mode 100644
index 00000000000..431213e25e4
--- /dev/null
+++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs
@@ -0,0 +1,33 @@
+#![deny(ambiguous_glob_reexports)]
+
+pub mod foo {
+    pub type X = u8;
+}
+
+pub mod bar {
+    pub type X = u8;
+    pub type Y = u8;
+}
+
+pub use foo::*;
+//~^ ERROR ambiguous glob re-exports
+pub use bar::*;
+
+mod ambiguous {
+    mod m1 { pub type A = u8; }
+    mod m2 { pub type A = u8; }
+    pub use self::m1::*;
+    //~^ ERROR ambiguous glob re-exports
+    pub use self::m2::*;
+}
+
+pub mod single {
+    pub use ambiguous::A;
+    //~^ ERROR `A` is ambiguous
+}
+
+pub mod glob {
+    pub use ambiguous::*;
+}
+
+pub fn main() {}
diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr
new file mode 100644
index 00000000000..07e61dd8643
--- /dev/null
+++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr
@@ -0,0 +1,47 @@
+error[E0659]: `A` is ambiguous
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:24
+   |
+LL |     pub use ambiguous::A;
+   |                        ^ ambiguous name
+   |
+   = note: ambiguous because of multiple glob imports of a name in the same module
+note: `A` could refer to the type alias imported here
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13
+   |
+LL |     pub use self::m1::*;
+   |             ^^^^^^^^^^^
+   = help: consider adding an explicit import of `A` to disambiguate
+note: `A` could also refer to the type alias imported here
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:21:13
+   |
+LL |     pub use self::m2::*;
+   |             ^^^^^^^^^^^
+   = help: consider adding an explicit import of `A` to disambiguate
+
+error: ambiguous glob re-exports
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:12:9
+   |
+LL | pub use foo::*;
+   |         ^^^^^^ the name `X` in the type namespace is first re-exported here
+LL |
+LL | pub use bar::*;
+   |         ------ but the name `X` in the type namespace is also re-exported here
+   |
+note: the lint level is defined here
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:1:9
+   |
+LL | #![deny(ambiguous_glob_reexports)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: ambiguous glob re-exports
+  --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13
+   |
+LL |     pub use self::m1::*;
+   |             ^^^^^^^^^^^ the name `A` in the type namespace is first re-exported here
+LL |
+LL |     pub use self::m2::*;
+   |             ----------- but the name `A` in the type namespace is also re-exported here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
index 6d7028c5e70..83f311efd39 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
@@ -2,7 +2,7 @@ error: the constant `N` is not of type `usize`
   --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
    |
 LL | impl<const N: i32> Copy for S<N> {}
-   |                             ^^^^
+   |                             ^^^^ expected `usize`, found `i32`
    |
 note: required by a bound in `S`
   --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr
index 437053a4476..35fdcae6a59 100644
--- a/tests/ui/statics/uninhabited-static.stderr
+++ b/tests/ui/statics/uninhabited-static.stderr
@@ -47,7 +47,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/uninhabited-static.rs:12:31
    |
 LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void
 
 warning: the type `Void` does not permit zero-initialization
   --> $DIR/uninhabited-static.rs:12:31
@@ -66,7 +66,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/uninhabited-static.rs:16:32
    |
 LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void
 
 warning: the type `Void` does not permit zero-initialization
   --> $DIR/uninhabited-static.rs:16:32
diff --git a/tests/ui/suggestions/issue-109436.rs b/tests/ui/suggestions/issue-109436.rs
new file mode 100644
index 00000000000..e45ee5991db
--- /dev/null
+++ b/tests/ui/suggestions/issue-109436.rs
@@ -0,0 +1,13 @@
+struct Foo;
+struct Bar;
+
+impl From<&Foo> for Bar {
+    fn from(foo: &Foo) -> Bar {
+        Bar
+    }
+}
+
+fn main() {
+    let foo = Foo;
+    let b: Bar = foo.into(); //~ ERROR E0277
+}
diff --git a/tests/ui/suggestions/issue-109436.stderr b/tests/ui/suggestions/issue-109436.stderr
new file mode 100644
index 00000000000..48518b33d12
--- /dev/null
+++ b/tests/ui/suggestions/issue-109436.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `Foo: Into<_>` is not satisfied
+  --> $DIR/issue-109436.rs:12:22
+   |
+LL |     let b: Bar = foo.into();
+   |                      ^^^^ the trait `~const Into<_>` is not implemented for `Foo`
+   |
+   = note: required for `Foo` to implement `Into<Bar>`
+help: consider borrowing here
+   |
+LL |     let b: Bar = (&foo).into();
+   |                  ++   +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs b/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs
new file mode 100644
index 00000000000..4bfb6323a53
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs
@@ -0,0 +1,40 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+trait Foo {
+    type Gat<'a>
+    where
+        Self: 'a;
+    fn bar(&self) -> Self::Gat<'_>;
+}
+
+enum Option<T> {
+    Some(T),
+    None,
+}
+
+impl<T> Option<T> {
+    fn as_ref(&self) -> Option<&T> {
+        match self {
+            Option::Some(t) => Option::Some(t),
+            Option::None => Option::None,
+        }
+    }
+
+    fn map<U>(self, f: impl FnOnce(T) -> U) -> Option<U> {
+        match self {
+            Option::Some(t) => Option::Some(f(t)),
+            Option::None => Option::None,
+        }
+    }
+}
+
+impl<T: Foo + 'static> Foo for Option<T> {
+    type Gat<'a> = Option<<T as Foo>::Gat<'a>> where Self: 'a;
+
+    fn bar(&self) -> Self::Gat<'_> {
+        self.as_ref().map(Foo::bar)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/alias-sub.rs b/tests/ui/traits/new-solver/alias-sub.rs
new file mode 100644
index 00000000000..30c1981a92e
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias-sub.rs
@@ -0,0 +1,34 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Trait {
+    type Assoc: Sized;
+}
+
+impl Trait for &'static str {
+    type Assoc = &'static str;
+}
+
+// Wrapper is just here to get around stupid `Sized` obligations in mir typeck
+struct Wrapper<T: ?Sized>(std::marker::PhantomData<T>);
+fn mk<T: Trait>(x: T) -> Wrapper<<T as Trait>::Assoc> { todo!() }
+
+
+trait IsStaticStr {}
+impl IsStaticStr for (&'static str,) {}
+fn define<T: IsStaticStr>(_: T) {}
+
+fn foo<'a, T: Trait>() {
+    let y = Default::default();
+
+    // `<?0 as Trait>::Assoc <: &'a str`
+    // In the old solver, this would *equate* the LHS and RHS.
+    let _: Wrapper<&'a str> = mk(y);
+
+    // ... then later on, we constrain `?0 = &'static str`
+    // but that should not mean that `'a = 'static`, because
+    // we should use *sub* above.
+    define((y,));
+}
+
+fn main() {}
diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr
index f0fa93722b8..bf947d0ea4a 100644
--- a/tests/ui/transmutability/issue-101739-1.stderr
+++ b/tests/ui/transmutability/issue-101739-1.stderr
@@ -8,7 +8,7 @@ error: the constant `ASSUME_ALIGNMENT` is not of type `Assume`
   --> $DIR/issue-101739-1.rs:8:14
    |
 LL |         Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>,
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Assume`, found `bool`
    |
 note: required by a bound in `BikeshedIntrinsicFrom`
   --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL