about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_abi/src/lib.rs1
-rw-r--r--compiler/rustc_arena/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs54
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs445
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs34
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_const_eval/messages.ftl108
-rw-r--r--compiler/rustc_const_eval/src/errors.rs154
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs102
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0092.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0093.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0094.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0208.md1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0211.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0230.md1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0231.md1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0232.md1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0264.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0439.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0539.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0542.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0543.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0544.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0545.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0546.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0547.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0549.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0622.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0773.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0789.md1
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_errors/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_feature/src/active.rs76
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs28
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs84
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs27
-rw-r--r--compiler/rustc_incremental/src/assert_module_sources.rs1
-rw-r--r--compiler/rustc_index/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl13
-rw-r--r--compiler/rustc_lint/src/builtin.rs59
-rw-r--r--compiler/rustc_lint/src/fn_null_check.rs112
-rw-r--r--compiler/rustc_lint/src/lib.rs9
-rw-r--r--compiler/rustc_lint/src/lints.rs33
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs146
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs1
-rw-r--r--compiler/rustc_macros/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs10
-rw-r--r--compiler/rustc_middle/src/hir/place.rs4
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs66
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs14
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs38
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs10
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs9
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs2
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs3
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs20
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs2
-rw-r--r--compiler/rustc_parse/messages.ftl10
-rw-r--r--compiler/rustc_parse/src/errors.rs27
-rw-r--r--compiler/rustc_parse/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs58
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/item.rs41
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs76
-rw-r--r--compiler/rustc_query_impl/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/edit_distance.rs3
-rw-r--r--compiler/rustc_span/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs94
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs141
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs40
-rw-r--r--compiler/rustc_type_ir/src/lib.rs6
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/core/src/intrinsics/mir.rs3
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ptr/mod.rs1
-rw-r--r--library/core/src/ptr/mut_ptr.rs1
-rw-r--r--library/panic_abort/src/lib.rs1
-rw-r--r--library/panic_unwind/src/lib.rs1
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--library/profiler_builtins/src/lib.rs1
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs18
-rw-r--r--library/test/src/lib.rs1
-rw-r--r--library/unwind/src/lib.rs1
-rw-r--r--src/bootstrap/check.rs6
-rw-r--r--src/bootstrap/compile.rs25
-rw-r--r--src/bootstrap/config.rs2
-rw-r--r--src/bootstrap/llvm.rs47
-rw-r--r--src/doc/rustdoc/src/unstable-features.md1
-rw-r--r--src/doc/unstable-book/src/language-features/intrinsics.md1
-rw-r--r--src/doc/unstable-book/src/language-features/lang-items.md3
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/tests/compile-test.rs1
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr4
-rw-r--r--src/tools/compiletest/src/runtest.rs35
-rw-r--r--src/tools/miri/src/diagnostics.rs4
-rw-r--r--src/tools/miri/tests/compiletest.rs1
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_float.stderr4
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_integer.stderr4
-rw-r--r--src/tools/rustfmt/src/parse/macros/mod.rs2
-rw-r--r--src/tools/tidy/src/features.rs1
-rw-r--r--tests/incremental/issue-61530.rs6
-rw-r--r--tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff8
-rw-r--r--tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff20
-rw-r--r--tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff18
-rw-r--r--tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff30
-rw-r--r--tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff29
-rw-r--r--tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff37
-rw-r--r--tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs11
-rw-r--r--tests/mir-opt/inline/inline_box_fn.call.Inline.panic-abort.diff32
-rw-r--r--tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff40
-rw-r--r--tests/mir-opt/inline/inline_box_fn.rs8
-rw-r--r--tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff18
-rw-r--r--tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff18
-rw-r--r--tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff24
-rw-r--r--tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff40
-rw-r--r--tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff20
-rw-r--r--tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff41
-rw-r--r--tests/run-make/tools.mk2
-rw-r--r--tests/rustdoc-gui/pocket-menu.goml73
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml2
-rw-r--r--tests/rustdoc-gui/src/staged_api/lib.rs1
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs1
-rw-r--r--tests/rustdoc-json/type/inherent_associated_type_bound.rs17
-rw-r--r--tests/rustdoc-json/type/inherent_associated_type_projections.rs12
-rw-r--r--tests/rustdoc/inherent-projections.rs10
-rw-r--r--tests/rustdoc/issue-18199.rs1
-rw-r--r--tests/ui/associated-inherent-types/issue-111879-0.rs4
-rw-r--r--tests/ui/associated-inherent-types/issue-111879-0.stderr6
-rw-r--r--tests/ui/associated-inherent-types/late-bound-regions.rs4
-rw-r--r--tests/ui/associated-inherent-types/late-bound-regions.stderr2
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr16
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr16
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.rs9
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs.stderr29
-rw-r--r--tests/ui/associated-inherent-types/substitute-params-bad.rs2
-rw-r--r--tests/ui/associated-inherent-types/substitute-params.rs3
-rw-r--r--tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs4
-rw-r--r--tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr55
-rw-r--r--tests/ui/const-ptr/forbidden_slices.stderr12
-rw-r--r--tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr54
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.32bit.stderr19
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.64bit.stderr19
-rw-r--r--tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/ub-enum.32bit.stderr10
-rw-r--r--tests/ui/consts/const-eval/ub-enum.64bit.stderr10
-rw-r--r--tests/ui/consts/const-eval/ub-int-array.32bit.stderr39
-rw-r--r--tests/ui/consts/const-eval/ub-int-array.64bit.stderr39
-rw-r--r--tests/ui/consts/const-eval/ub-int-array.rs84
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr6
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.stderr12
-rw-r--r--tests/ui/consts/extra-const-ub/detect-extra-ub.rs34
-rw-r--r--tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr34
-rw-r--r--tests/ui/consts/issue-83182.rs9
-rw-r--r--tests/ui/consts/issue-83182.stderr15
-rw-r--r--tests/ui/consts/issue-miri-1910.stderr2
-rw-r--r--tests/ui/consts/miri_unleashed/ptr_arith.rs4
-rw-r--r--tests/ui/consts/miri_unleashed/ptr_arith.stderr2
-rw-r--r--tests/ui/consts/ptr_is_null.rs1
-rw-r--r--tests/ui/did_you_mean/issue-114112.rs11
-rw-r--r--tests/ui/did_you_mean/issue-114112.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr7
-rw-r--r--tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs17
-rw-r--r--tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr (renamed from tests/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr)10
-rw-r--r--tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs10
-rw-r--r--tests/ui/lazy-type-alias/variance.rs38
-rw-r--r--tests/ui/lint/fn_null_check.rs30
-rw-r--r--tests/ui/lint/fn_null_check.stderr67
-rw-r--r--tests/ui/lint/ptr_null_checks.rs76
-rw-r--r--tests/ui/lint/ptr_null_checks.stderr225
-rw-r--r--tests/ui/parser/issues/issue-114219.rs4
-rw-r--r--tests/ui/parser/issues/issue-114219.stderr8
-rw-r--r--tests/ui/parser/issues/issue-22647.rs2
-rw-r--r--tests/ui/parser/issues/issue-22647.stderr9
-rw-r--r--tests/ui/parser/issues/issue-22712.rs2
-rw-r--r--tests/ui/parser/issues/issue-22712.stderr9
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.rs70
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.stderr74
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.rs18
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.stderr10
-rw-r--r--tests/ui/parser/pat-lt-bracket-3.rs3
-rw-r--r--tests/ui/parser/pat-lt-bracket-3.stderr9
-rw-r--r--tests/ui/parser/pat-lt-bracket-4.rs2
-rw-r--r--tests/ui/parser/pat-lt-bracket-4.stderr9
-rw-r--r--tests/ui/simd/intrinsic/generic-elements-pass.rs22
-rw-r--r--tests/ui/simd/intrinsic/generic-elements.rs22
-rw-r--r--tests/ui/simd/intrinsic/generic-elements.stderr74
-rw-r--r--tests/ui/simd/intrinsic/inlining-issue67557-ice.rs4
-rw-r--r--tests/ui/simd/intrinsic/inlining-issue67557.rs6
-rw-r--r--tests/ui/simd/shuffle-not-out-of-bounds.rs31
-rw-r--r--tests/ui/simd/shuffle-not-out-of-bounds.stderr50
-rw-r--r--tests/ui/simd/shuffle.rs3
-rw-r--r--tests/ui/suggestions/remove-question-symbol-with-paren.rs9
-rw-r--r--tests/ui/suggestions/remove-question-symbol-with-paren.stderr22
-rw-r--r--tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs2
-rw-r--r--triagebot.toml2
224 files changed, 2922 insertions, 1645 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 1442747fe1e..12dd1542d79 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,4 +1,5 @@
 #![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
+#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))]
 
 use std::fmt;
 #[cfg(feature = "nightly")]
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index ba47ebd68cb..f4900ece1cc 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -23,6 +23,7 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
 
 use smallvec::SmallVec;
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 317af8ae1f6..efe525c224d 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -11,6 +11,7 @@
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_middle;
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index abb11ce7396..50d875dfae9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -498,14 +498,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
     /// Checks that the types internal to the `place` match up with
     /// what would be expected.
+    #[instrument(level = "debug", skip(self, location), ret)]
     fn sanitize_place(
         &mut self,
         place: &Place<'tcx>,
         location: Location,
         context: PlaceContext,
     ) -> PlaceTy<'tcx> {
-        debug!("sanitize_place: {:?}", place);
-
         let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
 
         for elem in place.projection.iter() {
@@ -608,7 +607,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         }
     }
 
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self, location), ret, level = "debug")]
     fn sanitize_projection(
         &mut self,
         base: PlaceTy<'tcx>,
@@ -617,7 +616,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         location: Location,
         context: PlaceContext,
     ) -> PlaceTy<'tcx> {
-        debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
         let tcx = self.tcx();
         let base_ty = base.ty;
         match pi {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index d1c29f24ab9..9863e40b5b7 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -117,8 +117,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
-        _ if intrinsic.as_str().starts_with("simd_shuffle") => {
+        // simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U
+        sym::simd_shuffle => {
             let (x, y, idx) = match args {
                 [x, y, idx] => (x, y, idx),
                 _ => {
@@ -133,36 +133,26 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 return;
             }
 
-            // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
-            // If there is no suffix, use the index array length.
-            let n: u16 = if intrinsic == sym::simd_shuffle {
-                // Make sure this is actually an array, since typeck only checks the length-suffixed
-                // version of this intrinsic.
-                let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx));
-                match idx_ty.kind() {
-                    ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len
-                        .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
-                        .unwrap_or_else(|| {
-                            span_bug!(span, "could not evaluate shuffle index array length")
-                        })
-                        .try_into()
-                        .unwrap(),
-                    _ => {
-                        fx.tcx.sess.span_err(
-                            span,
-                            format!(
-                                "simd_shuffle index must be an array of `u32`, got `{}`",
-                                idx_ty,
-                            ),
-                        );
-                        // Prevent verifier error
-                        fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
-                        return;
-                    }
+            // Make sure this is actually an array, since typeck only checks the length-suffixed
+            // version of this intrinsic.
+            let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx));
+            let n: u16 = match idx_ty.kind() {
+                ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len
+                    .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
+                    .unwrap_or_else(|| {
+                        span_bug!(span, "could not evaluate shuffle index array length")
+                    })
+                    .try_into()
+                    .unwrap(),
+                _ => {
+                    fx.tcx.sess.span_err(
+                        span,
+                        format!("simd_shuffle index must be an array of `u32`, got `{}`", idx_ty),
+                    );
+                    // Prevent verifier error
+                    fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
+                    return;
                 }
-            } else {
-                // FIXME remove this case
-                intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap()
             };
 
             assert_eq!(x.layout(), y.layout());
@@ -179,7 +169,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             let indexes = {
                 use rustc_middle::mir::interpret::*;
                 let idx_const = crate::constant::mir_operand_get_const_val(fx, idx)
-                    .expect("simd_shuffle* idx not const");
+                    .expect("simd_shuffle idx not const");
 
                 let idx_bytes = match idx_const {
                     ConstValue::ByRef { alloc, offset } => {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index f27de867d36..85d3e7234a0 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -1,11 +1,11 @@
-#[cfg(feature="master")]
-use gccjit::{ComparisonOp, UnaryOp};
 use gccjit::ToRValue;
 use gccjit::{BinaryOp, RValue, Type};
+#[cfg(feature = "master")]
+use gccjit::{ComparisonOp, UnaryOp};
 
 use rustc_codegen_ssa::base::compare_simd_types;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-#[cfg(feature="master")]
+#[cfg(feature = "master")]
 use rustc_codegen_ssa::errors::ExpectedPointerMutability;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_codegen_ssa::mir::operand::OperandRef;
@@ -19,7 +19,7 @@ use rustc_span::{sym, Span, Symbol};
 use rustc_target::abi::Align;
 
 use crate::builder::Builder;
-#[cfg(feature="master")]
+#[cfg(feature = "master")]
 use crate::context::CodegenCx;
 
 pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
@@ -57,7 +57,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     let arg_tys = sig.inputs();
 
     if name == sym::simd_select_bitmask {
-        require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] });
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
+        );
         let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
 
         let expected_int_bits = (len.max(8) - 1).next_power_of_two();
@@ -95,7 +98,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         // NOTE: since the arguments can be vectors of floats, make sure the mask is a vector of
         // integer.
         let mask_element_type = bx.type_ix(arg1_element_type.get_size() as u64 * 8);
-        let vector_mask_type = bx.context.new_vector_type(mask_element_type, arg1_vector_type.get_num_units() as u64);
+        let vector_mask_type =
+            bx.context.new_vector_type(mask_element_type, arg1_vector_type.get_num_units() as u64);
 
         let mut elements = vec![];
         let one = bx.context.new_rvalue_one(mask.get_type());
@@ -149,38 +153,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         // compare them as equal, so bitcast.
         // FIXME(antoyo): allow comparing vector types as equal in libgccjit.
         let arg2 = bx.context.new_bitcast(None, args[1].immediate(), arg1.get_type());
-        return Ok(compare_simd_types(
-            bx,
-            arg1,
-            arg2,
-            in_elem,
-            llret_ty,
-            cmp_op,
-        ));
+        return Ok(compare_simd_types(bx, arg1, arg2, in_elem, llret_ty, cmp_op));
     }
 
-    if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
-        let n: u64 = if stripped.is_empty() {
-            // Make sure this is actually an array, since typeck only checks the length-suffixed
-            // version of this intrinsic.
-            match args[2].layout.ty.kind() {
-                ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
-                    len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
-                        || span_bug!(span, "could not evaluate shuffle index array length"),
-                    )
-                }
-                _ => return_error!(InvalidMonomorphization::SimdShuffle {
-                    span,
-                    name,
-                    ty: args[2].layout.ty
-                }),
+    if name == sym::simd_shuffle {
+        // Make sure this is actually an array, since typeck only checks the length-suffixed
+        // version of this intrinsic.
+        let n: u64 = match args[2].layout.ty.kind() {
+            ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
+                len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
+                    || span_bug!(span, "could not evaluate shuffle index array length"),
+                )
             }
-        } else {
-            stripped.parse().unwrap_or_else(|_| {
-                span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
-            })
+            _ => return_error!(InvalidMonomorphization::SimdShuffle {
+                span,
+                name,
+                ty: args[2].layout.ty
+            }),
         };
-
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
@@ -202,7 +192,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     if name == sym::simd_insert {
         require!(
             in_elem == arg_tys[2],
-            InvalidMonomorphization::InsertedType { span, name, in_elem, in_ty, out_ty: arg_tys[2] }
+            InvalidMonomorphization::InsertedType {
+                span,
+                name,
+                in_elem,
+                in_ty,
+                out_ty: arg_tys[2]
+            }
         );
         let vector = args[0].immediate();
         let index = args[1].immediate();
@@ -228,7 +224,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     if name == sym::simd_select {
         let m_elem_ty = in_elem;
         let m_len = in_len;
-        require_simd!(arg_tys[1], InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] });
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
+        );
         let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
         require!(
             m_len == v_len,
@@ -241,7 +240,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate()));
     }
 
-    #[cfg(feature="master")]
+    #[cfg(feature = "master")]
     if name == sym::simd_cast || name == sym::simd_as {
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
@@ -267,19 +266,17 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             Unsupported,
         }
 
-        let in_style =
-            match in_elem.kind() {
-                ty::Int(_) | ty::Uint(_) => Style::Int,
-                ty::Float(_) => Style::Float,
-                 _ => Style::Unsupported,
-            };
+        let in_style = match in_elem.kind() {
+            ty::Int(_) | ty::Uint(_) => Style::Int,
+            ty::Float(_) => Style::Float,
+            _ => Style::Unsupported,
+        };
 
-        let out_style =
-            match out_elem.kind() {
-                ty::Int(_) | ty::Uint(_) => Style::Int,
-                ty::Float(_) => Style::Float,
-                 _ => Style::Unsupported,
-            };
+        let out_style = match out_elem.kind() {
+            ty::Int(_) | ty::Uint(_) => Style::Int,
+            ty::Float(_) => Style::Float,
+            _ => Style::Unsupported,
+        };
 
         match (in_style, out_style) {
             (Style::Unsupported, Style::Unsupported) => {
@@ -294,7 +291,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                         out_elem
                     }
                 );
-            },
+            }
             _ => return Ok(bx.context.convert_vector(None, args[0].immediate(), llret_ty)),
         }
     }
@@ -342,10 +339,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         let mut shift = 0;
         for i in 0..in_len {
-            let elem = bx.extract_element(vector, bx.context.new_rvalue_from_int(bx.int_type, i as i32));
+            let elem =
+                bx.extract_element(vector, bx.context.new_rvalue_from_int(bx.int_type, i as i32));
             let shifted = elem >> sign_shift;
             let masked = shifted & one;
-            result = result | (bx.context.new_cast(None, masked, result_type) << bx.context.new_rvalue_from_int(result_type, shift));
+            result = result
+                | (bx.context.new_cast(None, masked, result_type)
+                    << bx.context.new_rvalue_from_int(result_type, shift));
             shift += 1;
         }
 
@@ -394,46 +394,50 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 return Err(());
             }};
         }
-        let (elem_ty_str, elem_ty) =
-            if let ty::Float(f) = in_elem.kind() {
-                let elem_ty = bx.cx.type_float_from_ty(*f);
-                match f.bit_width() {
-                    32 => ("f", elem_ty),
-                    64 => ("", elem_ty),
-                    _ => {
-                        return_error!(InvalidMonomorphization::FloatingPointVector { span, name, f_ty: *f, in_ty });
-                    }
+        let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
+            let elem_ty = bx.cx.type_float_from_ty(*f);
+            match f.bit_width() {
+                32 => ("f", elem_ty),
+                64 => ("", elem_ty),
+                _ => {
+                    return_error!(InvalidMonomorphization::FloatingPointVector {
+                        span,
+                        name,
+                        f_ty: *f,
+                        in_ty
+                    });
                 }
             }
-            else {
-                return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
-            };
+        } else {
+            return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
+        };
 
         let vec_ty = bx.cx.type_vector(elem_ty, in_len);
 
-        let intr_name =
-            match name {
-                sym::simd_ceil => "ceil",
-                sym::simd_fabs => "fabs", // TODO(antoyo): pand with 170141183420855150465331762880109871103
-                sym::simd_fcos => "cos",
-                sym::simd_fexp2 => "exp2",
-                sym::simd_fexp => "exp",
-                sym::simd_flog10 => "log10",
-                sym::simd_flog2 => "log2",
-                sym::simd_flog => "log",
-                sym::simd_floor => "floor",
-                sym::simd_fma => "fma",
-                sym::simd_fpowi => "__builtin_powi",
-                sym::simd_fpow => "pow",
-                sym::simd_fsin => "sin",
-                sym::simd_fsqrt => "sqrt",
-                sym::simd_round => "round",
-                sym::simd_trunc => "trunc",
-                _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name })
-            };
+        let intr_name = match name {
+            sym::simd_ceil => "ceil",
+            sym::simd_fabs => "fabs", // TODO(antoyo): pand with 170141183420855150465331762880109871103
+            sym::simd_fcos => "cos",
+            sym::simd_fexp2 => "exp2",
+            sym::simd_fexp => "exp",
+            sym::simd_flog10 => "log10",
+            sym::simd_flog2 => "log2",
+            sym::simd_flog => "log",
+            sym::simd_floor => "floor",
+            sym::simd_fma => "fma",
+            sym::simd_fpowi => "__builtin_powi",
+            sym::simd_fpow => "pow",
+            sym::simd_fsin => "sin",
+            sym::simd_fsqrt => "sqrt",
+            sym::simd_round => "round",
+            sym::simd_trunc => "trunc",
+            _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
+        };
         let builtin_name = format!("{}{}", intr_name, elem_ty_str);
         let funcs = bx.cx.functions.borrow();
-        let function = funcs.get(&builtin_name).unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name));
+        let function = funcs
+            .get(&builtin_name)
+            .unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name));
 
         // TODO(antoyo): add platform-specific behavior here for architectures that have these
         // intrinsics as instructions (for instance, gpus)
@@ -479,8 +483,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
     }
 
-    #[cfg(feature="master")]
-    fn vector_ty<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, elem_ty: Ty<'tcx>, vec_len: u64) -> Type<'gcc> {
+    #[cfg(feature = "master")]
+    fn vector_ty<'gcc, 'tcx>(
+        cx: &CodegenCx<'gcc, 'tcx>,
+        elem_ty: Ty<'tcx>,
+        vec_len: u64,
+    ) -> Type<'gcc> {
         // FIXME: use cx.layout_of(ty).llvm_type() ?
         let elem_ty = match *elem_ty.kind() {
             ty::Int(v) => cx.type_int_from_ty(v),
@@ -491,15 +499,22 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         cx.type_vector(elem_ty, vec_len)
     }
 
-    #[cfg(feature="master")]
-    fn gather<'a, 'gcc, 'tcx>(default: RValue<'gcc>, pointers: RValue<'gcc>, mask: RValue<'gcc>, pointer_count: usize, bx: &mut Builder<'a, 'gcc, 'tcx>, in_len: u64, underlying_ty: Ty<'tcx>, invert: bool) -> RValue<'gcc> {
-        let vector_type =
-            if pointer_count > 1 {
-                bx.context.new_vector_type(bx.usize_type, in_len)
-            }
-            else {
-                vector_ty(bx, underlying_ty, in_len)
-            };
+    #[cfg(feature = "master")]
+    fn gather<'a, 'gcc, 'tcx>(
+        default: RValue<'gcc>,
+        pointers: RValue<'gcc>,
+        mask: RValue<'gcc>,
+        pointer_count: usize,
+        bx: &mut Builder<'a, 'gcc, 'tcx>,
+        in_len: u64,
+        underlying_ty: Ty<'tcx>,
+        invert: bool,
+    ) -> RValue<'gcc> {
+        let vector_type = if pointer_count > 1 {
+            bx.context.new_vector_type(bx.usize_type, in_len)
+        } else {
+            vector_ty(bx, underlying_ty, in_len)
+        };
         let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type();
 
         let mut values = vec![];
@@ -530,13 +545,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         if invert {
             bx.shuffle_vector(vector, default, mask)
-        }
-        else {
+        } else {
             bx.shuffle_vector(default, vector, mask)
         }
     }
 
-    #[cfg(feature="master")]
+    #[cfg(feature = "master")]
     if name == sym::simd_gather {
         // simd_gather(values: <N x T>, pointers: <N x *_ T>,
         //             mask: <N x i{M}>) -> <N x T>
@@ -546,8 +560,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         // All types must be simd vector types
         require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
-        require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] });
-        require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] });
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
+        );
+        require_simd!(
+            arg_tys[2],
+            InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
+        );
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
         // Of the same length:
@@ -641,10 +661,19 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             }
         }
 
-        return Ok(gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, false));
+        return Ok(gather(
+            args[0].immediate(),
+            args[1].immediate(),
+            args[2].immediate(),
+            pointer_count,
+            bx,
+            in_len,
+            underlying_ty,
+            false,
+        ));
     }
 
-    #[cfg(feature="master")]
+    #[cfg(feature = "master")]
     if name == sym::simd_scatter {
         // simd_scatter(values: <N x T>, pointers: <N x *mut T>,
         //             mask: <N x i{M}>) -> ()
@@ -654,8 +683,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         // All types must be simd vector types
         require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
-        require_simd!(arg_tys[1], InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] });
-        require_simd!(arg_tys[2], InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] });
+        require_simd!(
+            arg_tys[1],
+            InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
+        );
+        require_simd!(
+            arg_tys[2],
+            InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
+        );
 
         // Of the same length:
         let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
@@ -744,17 +779,24 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             }
         }
 
-        let result = gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, true);
+        let result = gather(
+            args[0].immediate(),
+            args[1].immediate(),
+            args[2].immediate(),
+            pointer_count,
+            bx,
+            in_len,
+            underlying_ty,
+            true,
+        );
 
         let pointers = args[1].immediate();
 
-        let vector_type =
-            if pointer_count > 1 {
-                bx.context.new_vector_type(bx.usize_type, in_len)
-            }
-            else {
-                vector_ty(bx, underlying_ty, in_len)
-            };
+        let vector_type = if pointer_count > 1 {
+            bx.context.new_vector_type(bx.usize_type, in_len)
+        } else {
+            vector_ty(bx, underlying_ty, in_len)
+        };
         let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type();
 
         for i in 0..in_len {
@@ -809,11 +851,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         let rhs = args[1].immediate();
         let is_add = name == sym::simd_saturating_add;
         let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _;
-        let (signed, elem_width, elem_ty) =
-            match *in_elem.kind() {
-                ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)),
-                ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_uint_from_ty(i)),
-                _ => {
+        let (signed, elem_width, elem_ty) = match *in_elem.kind() {
+            ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)),
+            ty::Uint(i) => {
+                (false, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_uint_from_ty(i))
+            }
+            _ => {
                 return_error!(InvalidMonomorphization::ExpectedVectorElementType {
                     span,
                     name,
@@ -823,77 +866,82 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             }
         };
 
-        let result =
-            match (signed, is_add) {
-                (false, true) => {
-                    let res = lhs + rhs;
-                    let cmp = bx.context.new_comparison(None, ComparisonOp::LessThan, res, lhs);
-                    res | cmp
-                },
-                (true, true) => {
-                    // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition
-                    // TODO(antoyo): improve using conditional operators if possible.
-                    // TODO(antoyo): dyncast_vector should not require a call to unqualified.
-                    let arg_type = lhs.get_type().unqualified();
-                    // TODO(antoyo): convert lhs and rhs to unsigned.
-                    let sum = lhs + rhs;
-                    let vector_type = arg_type.dyncast_vector().expect("vector type");
-                    let unit = vector_type.get_num_units();
-                    let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1);
-                    let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]);
-
-                    let xor1 = lhs ^ rhs;
-                    let xor2 = lhs ^ sum;
-                    let and = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2;
-                    let mask = and >> width;
-
-                    let one = bx.context.new_rvalue_one(elem_ty);
-                    let ones = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]);
-                    let shift1 = ones << width;
-                    let shift2 = sum >> width;
-                    let mask_min = shift1 ^ shift2;
-
-                    let and1 = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum;
-                    let and2 = mask & mask_min;
-
-                    and1 + and2
-                },
-                (false, false) => {
-                    let res = lhs - rhs;
-                    let cmp = bx.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs);
-                    res & cmp
-                },
-                (true, false) => {
-                    // TODO(antoyo): dyncast_vector should not require a call to unqualified.
-                    let arg_type = lhs.get_type().unqualified();
-                    // TODO(antoyo): this uses the same algorithm from saturating add, but add the
-                    // negative of the right operand. Find a proper subtraction algorithm.
-                    let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs);
-
-                    // TODO(antoyo): convert lhs and rhs to unsigned.
-                    let sum = lhs + rhs;
-                    let vector_type = arg_type.dyncast_vector().expect("vector type");
-                    let unit = vector_type.get_num_units();
-                    let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1);
-                    let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]);
-
-                    let xor1 = lhs ^ rhs;
-                    let xor2 = lhs ^ sum;
-                    let and = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2;
-                    let mask = and >> width;
-
-                    let one = bx.context.new_rvalue_one(elem_ty);
-                    let ones = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]);
-                    let shift1 = ones << width;
-                    let shift2 = sum >> width;
-                    let mask_min = shift1 ^ shift2;
-
-                    let and1 = bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum;
-                    let and2 = mask & mask_min;
-
-                    and1 + and2
-                }
-            };
+        let result = match (signed, is_add) {
+            (false, true) => {
+                let res = lhs + rhs;
+                let cmp = bx.context.new_comparison(None, ComparisonOp::LessThan, res, lhs);
+                res | cmp
+            }
+            (true, true) => {
+                // Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition
+                // TODO(antoyo): improve using conditional operators if possible.
+                // TODO(antoyo): dyncast_vector should not require a call to unqualified.
+                let arg_type = lhs.get_type().unqualified();
+                // TODO(antoyo): convert lhs and rhs to unsigned.
+                let sum = lhs + rhs;
+                let vector_type = arg_type.dyncast_vector().expect("vector type");
+                let unit = vector_type.get_num_units();
+                let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1);
+                let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]);
+
+                let xor1 = lhs ^ rhs;
+                let xor2 = lhs ^ sum;
+                let and =
+                    bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2;
+                let mask = and >> width;
+
+                let one = bx.context.new_rvalue_one(elem_ty);
+                let ones =
+                    bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]);
+                let shift1 = ones << width;
+                let shift2 = sum >> width;
+                let mask_min = shift1 ^ shift2;
+
+                let and1 =
+                    bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum;
+                let and2 = mask & mask_min;
+
+                and1 + and2
+            }
+            (false, false) => {
+                let res = lhs - rhs;
+                let cmp = bx.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs);
+                res & cmp
+            }
+            (true, false) => {
+                // TODO(antoyo): dyncast_vector should not require a call to unqualified.
+                let arg_type = lhs.get_type().unqualified();
+                // TODO(antoyo): this uses the same algorithm from saturating add, but add the
+                // negative of the right operand. Find a proper subtraction algorithm.
+                let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs);
+
+                // TODO(antoyo): convert lhs and rhs to unsigned.
+                let sum = lhs + rhs;
+                let vector_type = arg_type.dyncast_vector().expect("vector type");
+                let unit = vector_type.get_num_units();
+                let a = bx.context.new_rvalue_from_int(elem_ty, ((elem_width as i32) << 3) - 1);
+                let width = bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![a; unit]);
+
+                let xor1 = lhs ^ rhs;
+                let xor2 = lhs ^ sum;
+                let and =
+                    bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, xor1) & xor2;
+                let mask = and >> width;
+
+                let one = bx.context.new_rvalue_one(elem_ty);
+                let ones =
+                    bx.context.new_rvalue_from_vector(None, lhs.get_type(), &vec![one; unit]);
+                let shift1 = ones << width;
+                let shift2 = sum >> width;
+                let mask_min = shift1 ^ shift2;
+
+                let and1 =
+                    bx.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, mask) & sum;
+                let and2 = mask & mask_min;
+
+                and1 + and2
+            }
+        };
 
         return Ok(result);
     }
@@ -968,7 +1016,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         1.0
     );
 
-
     macro_rules! minmax_red {
         ($name:ident: $int_red:ident, $float_red:ident) => {
             if name == sym::$name {
@@ -979,13 +1026,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 return match in_elem.kind() {
                     ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())),
                     ty::Float(_) => Ok(bx.$float_red(args[0].immediate())),
-                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { 
-                        span, 
+                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
+                        span,
                         name,
                         symbol: sym::$name,
                         in_ty,
-                        in_elem, 
-                        ret_ty 
+                        in_elem,
+                        ret_ty
                     }),
                 };
             }
@@ -1025,7 +1072,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 return match in_elem.kind() {
                     ty::Int(_) | ty::Uint(_) => {
                         let r = bx.vector_reduce_op(input, $op);
-                        Ok(if !$boolean { r } else { bx.icmp(IntPredicate::IntNE, r, bx.context.new_rvalue_zero(r.get_type())) })
+                        Ok(if !$boolean {
+                            r
+                        } else {
+                            bx.icmp(
+                                IntPredicate::IntNE,
+                                r,
+                                bx.context.new_rvalue_zero(r.get_type()),
+                            )
+                        })
                     }
                     _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
                         span,
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 86c39ab5e94..6f1e4c5178a 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1020,28 +1020,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         ));
     }
 
-    if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
-        // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
-        // If there is no suffix, use the index array length.
-        let n: u64 = if stripped.is_empty() {
-            // Make sure this is actually an array, since typeck only checks the length-suffixed
-            // version of this intrinsic.
-            match args[2].layout.ty.kind() {
-                ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
-                    len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
-                        || span_bug!(span, "could not evaluate shuffle index array length"),
-                    )
-                }
-                _ => return_error!(InvalidMonomorphization::SimdShuffle {
-                    span,
-                    name,
-                    ty: args[2].layout.ty
-                }),
+    if name == sym::simd_shuffle {
+        // Make sure this is actually an array, since typeck only checks the length-suffixed
+        // version of this intrinsic.
+        let n: u64 = match args[2].layout.ty.kind() {
+            ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
+                len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
+                    || span_bug!(span, "could not evaluate shuffle index array length"),
+                )
             }
-        } else {
-            stripped.parse().unwrap_or_else(|_| {
-                span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
-            })
+            _ => return_error!(InvalidMonomorphization::SimdShuffle {
+                span,
+                name,
+                ty: args[2].layout.ty
+            }),
         };
 
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 6582fd62387..8f383f68bcd 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -3,9 +3,6 @@ name = "rustc_codegen_ssa"
 version = "0.0.0"
 edition = "2021"
 
-[lib]
-test = false
-
 [dependencies]
 ar_archive_writer = "0.1.3"
 bitflags = "1.2.1"
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index f13dfd96b8e..4f26383ed05 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -862,11 +862,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     .iter()
                     .enumerate()
                     .map(|(i, arg)| {
-                        // The indices passed to simd_shuffle* in the
+                        // The indices passed to simd_shuffle in the
                         // third argument must be constant. This is
                         // checked by const-qualification, which also
                         // promotes any complex rvalues to constants.
-                        if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
+                        if i == 2 && intrinsic == sym::simd_shuffle {
                             if let mir::Operand::Constant(constant) = arg {
                                 let (llval, ty) = self.simd_shuffle_indices(&bx, constant);
                                 return OperandRef {
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 2905874eec5..0b336109921 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -15,9 +15,6 @@ const_eval_await_non_const =
     cannot convert `{$ty}` into a future in {const_eval_const_context}s
 const_eval_bounds_check_failed =
     indexing out of bounds: the len is {$len} but the index is {$index}
-const_eval_box_to_mut = {$front_matter}: encountered a box pointing to mutable memory in a constant
-const_eval_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
-const_eval_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
 const_eval_call_nonzero_intrinsic =
     `{$name}` called on 0
 
@@ -41,18 +38,12 @@ const_eval_const_context = {$kind ->
 const_eval_copy_nonoverlapping_overlapping =
     `copy_nonoverlapping` called on overlapping ranges
 
-const_eval_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
-const_eval_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)
-const_eval_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free)
 const_eval_dangling_int_pointer =
     {$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance)
 const_eval_dangling_null_pointer =
     {$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance)
 const_eval_dangling_ptr_in_final = encountered dangling pointer in final constant
 
-const_eval_dangling_ref_no_provenance = {$front_matter}: encountered a dangling reference ({$pointer} has no provenance)
-const_eval_dangling_ref_out_of_bounds = {$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)
-const_eval_dangling_ref_use_after_free = {$front_matter}: encountered a dangling reference (use-after-free)
 const_eval_dead_local =
     accessing a dead local variable
 const_eval_dealloc_immutable =
@@ -105,7 +96,6 @@ const_eval_error = {$error_kind ->
 const_eval_exact_div_has_remainder =
     exact_div: {$a} cannot be divided by {$b} without remainder
 
-const_eval_expected_non_ptr = {$front_matter}: encountered `{$value}`, but expected plain (non-pointer) bytes
 const_eval_fn_ptr_call =
     function pointers need an RFC before allowed to be called in {const_eval_const_context}s
 const_eval_for_loop_into_iter_non_const =
@@ -156,8 +146,6 @@ const_eval_invalid_align_details =
 
 const_eval_invalid_bool =
     interpreting an invalid 8-bit value as a bool: 0x{$value}
-const_eval_invalid_box_meta = {$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object
-const_eval_invalid_box_slice_meta = {$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object
 const_eval_invalid_char =
     interpreting an invalid 32-bit value as a char: 0x{$value}
 const_eval_invalid_dealloc =
@@ -168,16 +156,12 @@ const_eval_invalid_dealloc =
         *[other] {""}
     }
 
-const_eval_invalid_enum_tag = {$front_matter}: encountered {$value}, but expected a valid enum tag
-const_eval_invalid_fn_ptr = {$front_matter}: encountered {$value}, but expected a function pointer
 const_eval_invalid_function_pointer =
     using {$pointer} as function pointer but it does not point to a function
 const_eval_invalid_meta =
     invalid metadata in wide pointer: total size is bigger than largest supported object
 const_eval_invalid_meta_slice =
     invalid metadata in wide pointer: slice is bigger than largest supported object
-const_eval_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
-const_eval_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
 const_eval_invalid_str =
     this string is not valid UTF-8: {$err}
 const_eval_invalid_tag =
@@ -189,14 +173,10 @@ const_eval_invalid_uninit_bytes =
     reading memory at {$alloc}{$access}, but memory is uninitialized at {$uninit}, and this operation requires initialized memory
 const_eval_invalid_uninit_bytes_unknown =
     using uninitialized data, but this operation requires initialized memory
-const_eval_invalid_value = constructing invalid value
-const_eval_invalid_value_with_path = constructing invalid value at {$path}
-## The `front_matter`s here refer to either `middle_invalid_value` or `middle_invalid_value_with_path`.
 
 const_eval_invalid_vtable_pointer =
     using {$pointer} as vtable pointer but it does not point to a vtable
 
-const_eval_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
 
 const_eval_live_drop =
     destructor of `{$dropped_ty}` cannot be evaluated at compile-time
@@ -218,14 +198,13 @@ const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant
 const_eval_memory_access_test = memory access failed
 const_eval_memory_exhausted =
     tried to allocate more memory than available to compiler
+
 const_eval_modified_global =
     modifying a static's initial value from another static's initializer
 
 const_eval_mut_deref =
     mutation through a reference is not allowed in {const_eval_const_context}s
 
-const_eval_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const`
-const_eval_never_val = {$front_matter}: encountered a value of the never type `!`
 const_eval_non_const_fmt_macro_call =
     cannot call non-const formatting macro in {const_eval_const_context}s
 
@@ -241,10 +220,6 @@ const_eval_noreturn_asm_returned =
 const_eval_not_enough_caller_args =
     calling a function with fewer arguments than it requires
 
-const_eval_null_box = {$front_matter}: encountered a null box
-const_eval_null_fn_ptr = {$front_matter}: encountered a null function pointer
-const_eval_null_ref = {$front_matter}: encountered a null reference
-const_eval_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range}
 const_eval_nullary_intrinsic_fail =
     could not evaluate nullary intrinsic
 
@@ -257,7 +232,6 @@ const_eval_offset_from_underflow =
 
 const_eval_operator_non_const =
     cannot call non-const operator in {const_eval_const_context}s
-const_eval_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range}
 const_eval_overflow =
     overflow executing `{$name}`
 
@@ -287,7 +261,6 @@ const_eval_ptr_as_bytes_1 =
     this code performed an operation that depends on the underlying bytes representing a pointer
 const_eval_ptr_as_bytes_2 =
     the absolute address of a pointer is not known at compile-time, so such operations are not supported
-const_eval_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range}
 const_eval_question_branch_non_const =
     `?` cannot determine the branch of `{$ty}` in {const_eval_const_context}s
 
@@ -315,8 +288,8 @@ const_eval_raw_ptr_to_int =
 
 const_eval_read_extern_static =
     cannot read from extern static ({$did})
-const_eval_read_pointer_as_bytes =
-    unable to turn pointer into raw bytes
+const_eval_read_pointer_as_int =
+    unable to turn pointer into integer
 const_eval_realloc_or_alloc_with_offset =
     {$kind ->
         [dealloc] deallocating
@@ -324,9 +297,6 @@ const_eval_realloc_or_alloc_with_offset =
         *[other] {""}
     } {$ptr} which does not point to the beginning of an object
 
-const_eval_ref_to_mut = {$front_matter}: encountered a reference pointing to mutable memory in a constant
-const_eval_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant
-const_eval_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
 const_eval_remainder_by_zero =
     calculating the remainder with a divisor of zero
 const_eval_remainder_overflow =
@@ -363,8 +333,6 @@ const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in
 
 const_eval_try_block_from_output_non_const =
     `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s
-const_eval_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
-const_eval_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})
 const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s
 
 const_eval_unallowed_heap_allocations =
@@ -408,29 +376,14 @@ const_eval_undefined_behavior =
 const_eval_undefined_behavior_note =
     The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-const_eval_uninhabited_enum_tag = {$front_matter}: encountered an uninhabited enum variant
 const_eval_uninhabited_enum_variant_read =
     read discriminant of an uninhabited enum variant
 const_eval_uninhabited_enum_variant_written =
     writing discriminant of an uninhabited enum variant
-const_eval_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}`
-const_eval_uninit = {$front_matter}: encountered uninitialized bytes
-const_eval_uninit_bool = {$front_matter}: encountered uninitialized memory, but expected a boolean
-const_eval_uninit_box = {$front_matter}: encountered uninitialized memory, but expected a box
-const_eval_uninit_char = {$front_matter}: encountered uninitialized memory, but expected a unicode scalar value
-const_eval_uninit_enum_tag = {$front_matter}: encountered uninitialized bytes, but expected a valid enum tag
-const_eval_uninit_float = {$front_matter}: encountered uninitialized memory, but expected a floating point number
-const_eval_uninit_fn_ptr = {$front_matter}: encountered uninitialized memory, but expected a function pointer
-const_eval_uninit_init_scalar = {$front_matter}: encountered uninitialized memory, but expected initialized scalar value
-const_eval_uninit_int = {$front_matter}: encountered uninitialized memory, but expected an integer
-const_eval_uninit_raw_ptr = {$front_matter}: encountered uninitialized memory, but expected a raw pointer
-const_eval_uninit_ref = {$front_matter}: encountered uninitialized memory, but expected a reference
-const_eval_uninit_str = {$front_matter}: encountered uninitialized data in `str`
 const_eval_unreachable = entering unreachable code
 const_eval_unreachable_unwind =
     unwinding past a stack frame that does not allow unwinding
 
-const_eval_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
 const_eval_unsigned_offset_from_overflow =
     `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
 
@@ -453,8 +406,63 @@ const_eval_unwind_past_top =
 const_eval_upcast_mismatch =
     upcast on a pointer whose vtable does not match its type
 
+## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`.
+## (We'd love to sort this differently to make that more clear but tidy won't let us...)
+const_eval_validation_box_to_mut = {$front_matter}: encountered a box pointing to mutable memory in a constant
+const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
+const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
+const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
+const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)
+const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free)
+const_eval_validation_dangling_ref_no_provenance = {$front_matter}: encountered a dangling reference ({$pointer} has no provenance)
+const_eval_validation_dangling_ref_out_of_bounds = {$front_matter}: encountered a dangling reference (going beyond the bounds of its allocation)
+const_eval_validation_dangling_ref_use_after_free = {$front_matter}: encountered a dangling reference (use-after-free)
+
+const_eval_validation_expected_bool = expected a boolean
+const_eval_validation_expected_box = expected a box
+const_eval_validation_expected_char = expected a unicode scalar value
+const_eval_validation_expected_enum_tag = expected a valid enum tag
+const_eval_validation_expected_float = expected a floating point number
+const_eval_validation_expected_fn_ptr = expected a function pointer
+const_eval_validation_expected_init_scalar = expected initialized scalar value
+const_eval_validation_expected_int = expected an integer
+const_eval_validation_expected_raw_ptr = expected a raw pointer
+const_eval_validation_expected_ref = expected a reference
+const_eval_validation_expected_str = expected a string
+
+const_eval_validation_front_matter_invalid_value = constructing invalid value
+const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path}
+
 const_eval_validation_invalid_bool = {$front_matter}: encountered {$value}, but expected a boolean
+const_eval_validation_invalid_box_meta = {$front_matter}: encountered invalid box metadata: total size is bigger than largest supported object
+const_eval_validation_invalid_box_slice_meta = {$front_matter}: encountered invalid box metadata: slice is bigger than largest supported object
 const_eval_validation_invalid_char = {$front_matter}: encountered {$value}, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+
+const_eval_validation_invalid_enum_tag = {$front_matter}: encountered {$value}, but expected a valid enum tag
+const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, but expected a function pointer
+const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
+const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
+const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
+const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const`
+const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
+const_eval_validation_null_box = {$front_matter}: encountered a null box
+const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer
+const_eval_validation_null_ref = {$front_matter}: encountered a null reference
+const_eval_validation_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range}
+const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range}
+const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers
+const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected}
+const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range}
+const_eval_validation_ref_to_mut = {$front_matter}: encountered a reference pointing to mutable memory in a constant
+const_eval_validation_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant
+const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
+const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
+const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})
+const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant
+const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}`
+const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
+const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
+
 const_eval_write_to_read_only =
     writing to {$allocation} which is read-only
 const_eval_zst_pointer_out_of_bounds =
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 8cbc68d9061..3a4e2648b80 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -513,7 +513,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
             UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
             UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
-            Validation(e) => e.diagnostic_message(),
+            ValidationError(e) => e.diagnostic_message(),
             Custom(x) => (x.msg)(),
         }
     }
@@ -587,13 +587,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             InvalidUninitBytes(Some((alloc, info))) => {
                 builder.set_arg("alloc", alloc);
                 builder.set_arg("access", info.access);
-                builder.set_arg("uninit", info.uninit);
+                builder.set_arg("uninit", info.bad);
             }
             ScalarSizeMismatch(info) => {
                 builder.set_arg("target_size", info.target_size);
                 builder.set_arg("data_size", info.data_size);
             }
-            Validation(e) => e.add_args(handler, builder),
+            ValidationError(e) => e.add_args(handler, builder),
             Custom(custom) => {
                 (custom.add_args)(&mut |name, value| {
                     builder.set_arg(name, value);
@@ -608,74 +608,72 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         use crate::fluent_generated::*;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
         match self.kind {
-            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => const_eval_box_to_uninhabited,
-            PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => const_eval_ref_to_uninhabited,
-
-            PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_box_to_static,
-            PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_ref_to_static,
-
-            PtrToMut { ptr_kind: PointerKind::Box } => const_eval_box_to_mut,
-            PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_ref_to_mut,
-
-            ExpectedNonPtr { .. } => const_eval_expected_non_ptr,
-            MutableRefInConst => const_eval_mutable_ref_in_const,
-            NullFnPtr => const_eval_null_fn_ptr,
-            NeverVal => const_eval_never_val,
-            NullablePtrOutOfRange { .. } => const_eval_nullable_ptr_out_of_range,
-            PtrOutOfRange { .. } => const_eval_ptr_out_of_range,
-            OutOfRange { .. } => const_eval_out_of_range,
-            UnsafeCell => const_eval_unsafe_cell,
-            UninhabitedVal { .. } => const_eval_uninhabited_val,
-            InvalidEnumTag { .. } => const_eval_invalid_enum_tag,
-            UninhabitedEnumTag => const_eval_uninhabited_enum_tag,
-            UninitEnumTag => const_eval_uninit_enum_tag,
-            UninitStr => const_eval_uninit_str,
-            Uninit { expected: ExpectedKind::Bool } => const_eval_uninit_bool,
-            Uninit { expected: ExpectedKind::Reference } => const_eval_uninit_ref,
-            Uninit { expected: ExpectedKind::Box } => const_eval_uninit_box,
-            Uninit { expected: ExpectedKind::RawPtr } => const_eval_uninit_raw_ptr,
-            Uninit { expected: ExpectedKind::InitScalar } => const_eval_uninit_init_scalar,
-            Uninit { expected: ExpectedKind::Char } => const_eval_uninit_char,
-            Uninit { expected: ExpectedKind::Float } => const_eval_uninit_float,
-            Uninit { expected: ExpectedKind::Int } => const_eval_uninit_int,
-            Uninit { expected: ExpectedKind::FnPtr } => const_eval_uninit_fn_ptr,
-            UninitVal => const_eval_uninit,
-            InvalidVTablePtr { .. } => const_eval_invalid_vtable_ptr,
+            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
+                const_eval_validation_box_to_uninhabited
+            }
+            PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => {
+                const_eval_validation_ref_to_uninhabited
+            }
+
+            PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static,
+            PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static,
+
+            PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut,
+            PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_mut,
+
+            PointerAsInt { .. } => const_eval_validation_pointer_as_int,
+            PartialPointer => const_eval_validation_partial_pointer,
+            MutableRefInConst => const_eval_validation_mutable_ref_in_const,
+            NullFnPtr => const_eval_validation_null_fn_ptr,
+            NeverVal => const_eval_validation_never_val,
+            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
+            PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
+            OutOfRange { .. } => const_eval_validation_out_of_range,
+            UnsafeCell => const_eval_validation_unsafe_cell,
+            UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
+            InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
+            UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
+            Uninit { .. } => const_eval_validation_uninit,
+            InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
             InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
-                const_eval_invalid_box_slice_meta
+                const_eval_validation_invalid_box_slice_meta
             }
             InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref } => {
-                const_eval_invalid_ref_slice_meta
+                const_eval_validation_invalid_ref_slice_meta
             }
 
-            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => const_eval_invalid_box_meta,
-            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => const_eval_invalid_ref_meta,
-            UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_unaligned_ref,
-            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_unaligned_box,
+            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
+                const_eval_validation_invalid_box_meta
+            }
+            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => {
+                const_eval_validation_invalid_ref_meta
+            }
+            UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_validation_unaligned_ref,
+            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
 
-            NullPtr { ptr_kind: PointerKind::Box } => const_eval_null_box,
-            NullPtr { ptr_kind: PointerKind::Ref } => const_eval_null_ref,
+            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
+            NullPtr { ptr_kind: PointerKind::Ref } => const_eval_validation_null_ref,
             DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
-                const_eval_dangling_box_no_provenance
+                const_eval_validation_dangling_box_no_provenance
             }
             DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref, .. } => {
-                const_eval_dangling_ref_no_provenance
+                const_eval_validation_dangling_ref_no_provenance
             }
             DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
-                const_eval_dangling_box_out_of_bounds
+                const_eval_validation_dangling_box_out_of_bounds
             }
             DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref } => {
-                const_eval_dangling_ref_out_of_bounds
+                const_eval_validation_dangling_ref_out_of_bounds
             }
             DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
-                const_eval_dangling_box_use_after_free
+                const_eval_validation_dangling_box_use_after_free
             }
             DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref } => {
-                const_eval_dangling_ref_use_after_free
+                const_eval_validation_dangling_ref_use_after_free
             }
             InvalidBool { .. } => const_eval_validation_invalid_bool,
             InvalidChar { .. } => const_eval_validation_invalid_char,
-            InvalidFnPtr { .. } => const_eval_invalid_fn_ptr,
+            InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr,
         }
     }
 
@@ -683,13 +681,21 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         use crate::fluent_generated as fluent;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
 
+        if let PointerAsInt { .. } | PartialPointer = self.kind {
+            err.help(fluent::const_eval_ptr_as_bytes_1);
+            err.help(fluent::const_eval_ptr_as_bytes_2);
+        }
+
         let message = if let Some(path) = self.path {
             handler.eagerly_translate_to_string(
-                fluent::const_eval_invalid_value_with_path,
+                fluent::const_eval_validation_front_matter_invalid_value_with_path,
                 [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
             )
         } else {
-            handler.eagerly_translate_to_string(fluent::const_eval_invalid_value, [].into_iter())
+            handler.eagerly_translate_to_string(
+                fluent::const_eval_validation_front_matter_invalid_value,
+                [].into_iter(),
+            )
         };
 
         err.set_arg("front_matter", message);
@@ -729,8 +735,24 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
                 err.set_arg("ty", ty);
             }
-            ExpectedNonPtr { value }
-            | InvalidEnumTag { value }
+            PointerAsInt { expected } | Uninit { expected } => {
+                let msg = match expected {
+                    ExpectedKind::Reference => fluent::const_eval_validation_expected_ref,
+                    ExpectedKind::Box => fluent::const_eval_validation_expected_box,
+                    ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr,
+                    ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar,
+                    ExpectedKind::Bool => fluent::const_eval_validation_expected_bool,
+                    ExpectedKind::Char => fluent::const_eval_validation_expected_char,
+                    ExpectedKind::Float => fluent::const_eval_validation_expected_float,
+                    ExpectedKind::Int => fluent::const_eval_validation_expected_int,
+                    ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr,
+                    ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
+                    ExpectedKind::Str => fluent::const_eval_validation_expected_str,
+                };
+                let msg = handler.eagerly_translate_to_string(msg, [].into_iter());
+                err.set_arg("expected", msg);
+            }
+            InvalidEnumTag { value }
             | InvalidVTablePtr { value }
             | InvalidBool { value }
             | InvalidChar { value }
@@ -758,15 +780,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             | NullFnPtr
             | NeverVal
             | UnsafeCell
-            | UninitEnumTag
-            | UninitStr
-            | Uninit { .. }
-            | UninitVal
             | InvalidMetaSliceTooLarge { .. }
             | InvalidMetaTooLarge { .. }
             | DanglingPtrUseAfterFree { .. }
             | DanglingPtrOutOfBounds { .. }
-            | UninhabitedEnumTag => {}
+            | UninhabitedEnumVariant
+            | PartialPointer => {}
         }
     }
 }
@@ -776,9 +795,9 @@ impl ReportErrorExt for UnsupportedOpInfo {
         use crate::fluent_generated::*;
         match self {
             UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
-            UnsupportedOpInfo::PartialPointerOverwrite(_) => const_eval_partial_pointer_overwrite,
-            UnsupportedOpInfo::PartialPointerCopy(_) => const_eval_partial_pointer_copy,
-            UnsupportedOpInfo::ReadPointerAsBytes => const_eval_read_pointer_as_bytes,
+            UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
+            UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
+            UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
             UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
             UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static,
         }
@@ -787,13 +806,16 @@ impl ReportErrorExt for UnsupportedOpInfo {
         use crate::fluent_generated::*;
 
         use UnsupportedOpInfo::*;
-        if let ReadPointerAsBytes | PartialPointerOverwrite(_) | PartialPointerCopy(_) = self {
+        if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
             builder.help(const_eval_ptr_as_bytes_1);
             builder.help(const_eval_ptr_as_bytes_2);
         }
         match self {
-            Unsupported(_) | ReadPointerAsBytes => {}
-            PartialPointerOverwrite(ptr) | PartialPointerCopy(ptr) => {
+            // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
+            // be further processed by validity checking which then turns it into something nice to
+            // print. So it's not worth the effort of having diagnostics that can print the `info`.
+            Unsupported(_) | ReadPointerAsInt(_) => {}
+            OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
                 builder.set_arg("ptr", ptr);
             }
             ThreadLocalStatic(did) | ReadExternStatic(did) => {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index ff22d3d2d5a..d3f05af1c72 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -25,13 +25,17 @@ use rustc_target::abi::{
 
 use std::hash::Hash;
 
-// for the validation errors
-use super::UndefinedBehaviorInfo::*;
 use super::{
     AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
     Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor,
 };
 
+// for the validation errors
+use super::InterpError::UndefinedBehavior as Ub;
+use super::InterpError::Unsupported as Unsup;
+use super::UndefinedBehaviorInfo::*;
+use super::UnsupportedOpInfo::*;
+
 macro_rules! throw_validation_failure {
     ($where:expr, $kind: expr) => {{
         let where_ = &$where;
@@ -43,7 +47,7 @@ macro_rules! throw_validation_failure {
             None
         };
 
-        throw_ub!(Validation(ValidationErrorInfo { path, kind: $kind }))
+        throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind }))
     }};
 }
 
@@ -85,16 +89,16 @@ macro_rules! try_validation {
             Ok(x) => x,
             // We catch the error and turn it into a validation failure. We are okay with
             // allocation here as this can only slow down builds that fail anyway.
-            Err(e) => match e.into_parts() {
+            Err(e) => match e.kind() {
                 $(
-                    (InterpError::UndefinedBehavior($($p)|+), _) =>
+                    $($p)|+ =>
                        throw_validation_failure!(
                             $where,
                             $kind
                         )
                 ),+,
                 #[allow(unreachable_patterns)]
-                (e, rest) => Err::<!, _>($crate::interpret::InterpErrorInfo::from_parts(e, rest))?,
+                _ => Err::<!, _>(e)?,
             }
         }
     }};
@@ -294,7 +298,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         Ok(try_validation!(
             self.ecx.read_immediate(op),
             self.path,
-            InvalidUninitBytes(None) => Uninit { expected }
+            Ub(InvalidUninitBytes(None)) =>
+                Uninit { expected },
+            // The `Unsup` cases can only occur during CTFE
+            Unsup(ReadPointerAsInt(_)) =>
+                PointerAsInt { expected },
+            Unsup(ReadPartialPointer(_)) =>
+                PartialPointer,
         ))
     }
 
@@ -319,8 +329,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 let (_ty, _trait) = try_validation!(
                     self.ecx.get_ptr_vtable(vtable),
                     self.path,
-                    DanglingIntPointer(..) |
-                    InvalidVTablePointer(..) => InvalidVTablePtr { value: format!("{vtable}") }
+                    Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
+                        InvalidVTablePtr { value: format!("{vtable}") }
                 );
                 // FIXME: check if the type/trait match what ty::Dynamic says?
             }
@@ -356,7 +366,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         let size_and_align = try_validation!(
             self.ecx.size_and_align_of_mplace(&place),
             self.path,
-            InvalidMeta(msg) => match msg {
+            Ub(InvalidMeta(msg)) => match msg {
                 InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind },
                 InvalidMetaKind::TooBig => InvalidMetaTooLarge { ptr_kind },
             }
@@ -375,23 +385,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
-            AlignmentCheckFailed { required, has } => UnalignedPtr {
+            Ub(AlignmentCheckFailed { required, has }) => UnalignedPtr {
                 ptr_kind,
                 required_bytes: required.bytes(),
                 found_bytes: has.bytes()
             },
-            DanglingIntPointer(0, _) => NullPtr { ptr_kind },
-            DanglingIntPointer(i, _) => DanglingPtrNoProvenance {
+            Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind },
+            Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance {
                 ptr_kind,
                 // FIXME this says "null pointer" when null but we need translate
-                pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(i))
+                pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(*i))
             },
-            PointerOutOfBounds { .. } => DanglingPtrOutOfBounds {
+            Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
                 ptr_kind
             },
             // This cannot happen during const-eval (because interning already detects
             // dangling pointers), but it can happen in Miri.
-            PointerUseAfterFree(..) => DanglingPtrUseAfterFree {
+            Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
                 ptr_kind,
             },
         );
@@ -477,7 +487,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 try_validation!(
                     value.to_bool(),
                     self.path,
-                    InvalidBool(..) => ValidationErrorKind::InvalidBool {
+                    Ub(InvalidBool(..)) => ValidationErrorKind::InvalidBool {
                         value: format!("{value:x}"),
                     }
                 );
@@ -488,7 +498,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 try_validation!(
                     value.to_char(),
                     self.path,
-                    InvalidChar(..) => ValidationErrorKind::InvalidChar {
+                    Ub(InvalidChar(..)) => ValidationErrorKind::InvalidChar {
                         value: format!("{value:x}"),
                     }
                 );
@@ -497,7 +507,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
                 // NOTE: Keep this in sync with the array optimization for int/float
                 // types below!
-                let value = self.read_scalar(
+                self.read_scalar(
                     value,
                     if matches!(ty.kind(), ty::Float(..)) {
                         ExpectedKind::Float
@@ -505,14 +515,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                         ExpectedKind::Int
                     },
                 )?;
-                // As a special exception we *do* match on a `Scalar` here, since we truly want
-                // to know its underlying representation (and *not* cast it to an integer).
-                if matches!(value, Scalar::Ptr(..)) {
-                    throw_validation_failure!(
-                        self.path,
-                        ExpectedNonPtr { value: format!("{value:x}") }
-                    )
-                }
                 Ok(true)
             }
             ty::RawPtr(..) => {
@@ -546,10 +548,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     let _fn = try_validation!(
                         self.ecx.get_ptr_fn(ptr),
                         self.path,
-                        DanglingIntPointer(..) |
-                        InvalidFunctionPointer(..) => InvalidFnPtr {
-                            value: format!("{ptr}"),
-                        },
+                        Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) =>
+                            InvalidFnPtr { value: format!("{ptr}") },
                     );
                     // FIXME: Check if the signature matches
                 } else {
@@ -657,11 +657,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
             Ok(try_validation!(
                 this.ecx.read_discriminant(op),
                 this.path,
-                InvalidTag(val) => InvalidEnumTag {
+                Ub(InvalidTag(val)) => InvalidEnumTag {
                     value: format!("{val:x}"),
                 },
-                UninhabitedEnumVariantRead(_) => UninhabitedEnumTag,
-                InvalidUninitBytes(None) => UninitEnumTag,
+                Ub(UninhabitedEnumVariantRead(_)) => UninhabitedEnumVariant,
+                // Uninit / bad provenance are not possible since the field was already previously
+                // checked at its integer type.
             ))
         })
     }
@@ -740,7 +741,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 try_validation!(
                     self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len)),
                     self.path,
-                    InvalidUninitBytes(..) => { UninitStr },
+                    Ub(InvalidUninitBytes(..)) => Uninit { expected: ExpectedKind::Str },
+                    Unsup(ReadPointerAsInt(_)) => PointerAsInt { expected: ExpectedKind::Str }
                 );
             }
             ty::Array(tys, ..) | ty::Slice(tys)
@@ -752,6 +754,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..))
                 =>
             {
+                let expected = if tys.is_integral() { ExpectedKind::Int } else { ExpectedKind::Float };
                 // Optimized handling for arrays of integer/float type.
 
                 // This is the length of the array/slice.
@@ -770,7 +773,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                     Left(mplace) => mplace,
                     Right(imm) => match *imm {
                         Immediate::Uninit =>
-                            throw_validation_failure!(self.path, UninitVal),
+                            throw_validation_failure!(self.path, Uninit { expected }),
                         Immediate::Scalar(..) | Immediate::ScalarPair(..) =>
                             bug!("arrays/slices can never have Scalar/ScalarPair layout"),
                     }
@@ -796,17 +799,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                         // For some errors we might be able to provide extra information.
                         // (This custom logic does not fit the `try_validation!` macro.)
                         match err.kind() {
-                            err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => {
+                            Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => {
                                 // Some byte was uninitialized, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
                                 let i = usize::try_from(
-                                    access.uninit.start.bytes() / layout.size.bytes(),
+                                    access.bad.start.bytes() / layout.size.bytes(),
                                 )
                                 .unwrap();
                                 self.path.push(PathElem::ArrayElem(i));
 
-                                throw_validation_failure!(self.path, UninitVal)
+                                if matches!(err.kind(), Ub(InvalidUninitBytes(_))) {
+                                    throw_validation_failure!(self.path, Uninit { expected })
+                                } else {
+                                    throw_validation_failure!(self.path, PointerAsInt { expected })
+                                }
                             }
 
                             // Propagate upwards (that will also check for unexpected errors).
@@ -892,17 +899,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Run it.
         match visitor.visit_value(&op) {
             Ok(()) => Ok(()),
-            // Pass through validation failures.
-            Err(err) if matches!(err.kind(), err_ub!(Validation { .. })) => Err(err),
-            // Complain about any other kind of UB error -- those are bad because we'd like to
+            // Pass through validation failures and "invalid program" issues.
+            Err(err)
+                if matches!(
+                    err.kind(),
+                    err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_)
+                ) =>
+            {
+                Err(err)
+            }
+            // Complain about any other kind of error -- those are bad because we'd like to
             // report them in a way that shows *where* in the value the issue lies.
-            Err(err) if matches!(err.kind(), InterpError::UndefinedBehavior(_)) => {
+            Err(err) => {
                 let (err, backtrace) = err.into_parts();
                 backtrace.print_backtrace();
                 bug!("Unexpected Undefined Behavior error during validation: {err:?}");
             }
-            // Pass through everything else.
-            Err(err) => Err(err),
         }
     }
 
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 3deb9c5c2f5..33772089744 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -37,6 +37,7 @@
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 #[macro_use]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md
index 5cbe2a188b0..84ec0656d1a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0092.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0092.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0092
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     fn atomic_foo(); // error: unrecognized atomic operation
@@ -17,6 +18,7 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in
 
 ```
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     fn atomic_fence_seqcst(); // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md
index b1683cf4fc4..2bda4d74f72 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0093.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0093.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0093
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     fn foo(); // error: unrecognized intrinsic function: `foo`
@@ -22,6 +23,7 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in
 
 ```
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     fn atomic_fence_seqcst(); // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md
index cc546bdbb3b..67a8c3678c5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0094.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0094.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0094
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
@@ -18,6 +19,7 @@ Example:
 
 ```
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md
index c6db9b5d61b..2b811b4b850 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0208.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0208.md
@@ -8,6 +8,7 @@ Erroneous code example:
 ```compile_fail
 // NOTE: this feature is perma-unstable and should *only* be used for
 //       testing purposes.
+#![allow(internal_features)]
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md
index 8c2462ebd9b..70f14fffae6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0211.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0211.md
@@ -5,6 +5,7 @@ used. Erroneous code examples:
 
 ```compile_fail
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
@@ -41,6 +42,7 @@ For the first code example, please check the function definition. Example:
 
 ```
 #![feature(intrinsics)]
+#![allow(internal_features)]
 
 extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0230.md b/compiler/rustc_error_codes/src/error_codes/E0230.md
index cfb72e74319..87ea90e73c9 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0230.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0230.md
@@ -5,6 +5,7 @@ compiled:
 
 ```compile_fail,E0230
 #![feature(rustc_attrs)]
+#![allow(internal_features)]
 
 #[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{B}>`"] // error
 trait BadAnnotation<A> {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0231.md b/compiler/rustc_error_codes/src/error_codes/E0231.md
index 23a0a88ecdd..a1aaf90df49 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0231.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0231.md
@@ -5,6 +5,7 @@ compiled:
 
 ```compile_fail,E0231
 #![feature(rustc_attrs)]
+#![allow(internal_features)]
 
 #[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{}>`"] // error!
 trait BadAnnotation<A> {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0232.md b/compiler/rustc_error_codes/src/error_codes/E0232.md
index b310caefa6e..0e50cf589ee 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0232.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0232.md
@@ -5,6 +5,7 @@ compiled:
 
 ```compile_fail,E0232
 #![feature(rustc_attrs)]
+#![allow(internal_features)]
 
 #[rustc_on_unimplemented(lorem="")] // error!
 trait BadAnnotation {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md
index e2a27f7b106..d7906076229 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0264.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0264.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0264
 #![feature(lang_items)]
+#![allow(internal_features)]
 
 extern "C" {
     #[lang = "cake"] // error: unknown external lang item: `cake`
@@ -16,6 +17,7 @@ A list of available external lang items is available in
 
 ```
 #![feature(lang_items)]
+#![allow(internal_features)]
 
 extern "C" {
     #[lang = "panic_impl"] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md
index 24268aef222..369226c383e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0439.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0439.md
@@ -16,7 +16,7 @@ extern "platform-intrinsic" {
 The `simd_shuffle` function needs the length of the array passed as
 last parameter in its name. Example:
 
-```
+```ignore (no longer compiles)
 #![feature(platform_intrinsics)]
 
 extern "platform-intrinsic" {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index c53d60a5f47..cd28afbc48d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0539
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[deprecated(note)] // error!
@@ -28,6 +29,7 @@ To fix these issues you need to give required key-value pairs.
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[deprecated(since = "1.39.0", note = "reason")] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
index c69e574179b..be186dbd2cc 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0542.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0542
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(feature = "_stable_fn")] // invalid
@@ -23,6 +24,7 @@ To fix this issue, you need to provide the `since` field. Example:
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(feature = "_stable_fn", since = "1.0.0")] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0543.md b/compiler/rustc_error_codes/src/error_codes/E0543.md
index d0b2e2f7a7d..5051c72a151 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0543.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0543.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0543
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "0.1.0", feature = "_deprecated_fn")]
@@ -17,6 +18,7 @@ To fix this issue, you need to provide the `note` field. Example:
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "0.1.0", feature = "_deprecated_fn")]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0544.md b/compiler/rustc_error_codes/src/error_codes/E0544.md
index 2227e2a06bf..202401f9d45 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0544.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0544.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0544
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "rust1")]
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -15,6 +16,7 @@ To fix this issue, ensure that each item has at most one stability attribute.
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "rust1")]
 
 #[stable(feature = "test", since = "2.0.0")] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0545.md b/compiler/rustc_error_codes/src/error_codes/E0545.md
index 7aba084f4d3..880378ebd3a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0545.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0545.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0545
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[unstable(feature = "_unstable_fn", issue = "0")] // invalid
@@ -18,6 +19,7 @@ Example:
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[unstable(feature = "_unstable_fn", issue = "none")] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md
index a33dcb7a9ac..8c98eaa07bb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0546.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0546.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0546
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[unstable(issue = "none")] // invalid
@@ -17,6 +18,7 @@ To fix this issue, you need to provide the `feature` field. Example:
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[unstable(feature = "unstable_fn", issue = "none")] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0547.md b/compiler/rustc_error_codes/src/error_codes/E0547.md
index 4950325df64..5b0f7cd44cf 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0547.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0547.md
@@ -4,6 +4,7 @@ Erroneous code example:
 
 ```compile_fail,E0547
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[unstable(feature = "_unstable_fn")] // invalid
@@ -17,6 +18,7 @@ To fix this issue, you need to provide the `issue` field. Example:
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[unstable(feature = "_unstable_fn", issue = "none")] // ok!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
index 70e458a9867..cc6a47fe253 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0549.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -5,6 +5,7 @@ Erroneous code example:
 
 ```compile_fail,E0549
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[deprecated(
@@ -19,6 +20,7 @@ Example:
 
 ```
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "1.0.0", feature = "test")]
diff --git a/compiler/rustc_error_codes/src/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md
index 3ba3ed10e5c..5d71ee9949d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0622.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0622.md
@@ -4,6 +4,8 @@ Erroneous code example:
 
 ```compile_fail,E0622
 #![feature(intrinsics)]
+#![allow(internal_features)]
+
 extern "rust-intrinsic" {
     pub static breakpoint: fn(); // error: intrinsic must be a function
 }
@@ -17,6 +19,8 @@ error, just declare a function. Example:
 
 ```no_run
 #![feature(intrinsics)]
+#![allow(internal_features)]
+
 extern "rust-intrinsic" {
     pub fn breakpoint(); // ok!
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md
index b19a58bf33d..aa65a475a4f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0773.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0773.md
@@ -5,6 +5,7 @@ Erroneous code example:
 ```compile_fail,E0773
 #![feature(decl_macro)]
 #![feature(rustc_attrs)]
+#![allow(internal_features)]
 
 #[rustc_builtin_macro]
 pub macro test($item:item) {
@@ -24,6 +25,7 @@ To fix the issue, remove the duplicate declaration:
 ```
 #![feature(decl_macro)]
 #![feature(rustc_attrs)]
+#![allow(internal_features)]
 
 #[rustc_builtin_macro]
 pub macro test($item:item) {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0789.md b/compiler/rustc_error_codes/src/error_codes/E0789.md
index 89b7cd422fe..2c0018cc799 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0789.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0789.md
@@ -10,6 +10,7 @@ Erroneous code example:
 //       used outside of the compiler and standard library.
 #![feature(rustc_attrs)]
 #![feature(staged_api)]
+#![allow(internal_features)]
 
 #![unstable(feature = "foo_module", reason = "...", issue = "123")]
 
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 77e2c900c0d..3bf15505090 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(type_alias_impl_trait)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 3d1639db4af..3b753629128 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -15,6 +15,7 @@
 #![feature(box_patterns)]
 #![feature(error_reporter)]
 #![allow(incomplete_features)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 83a5043b0aa..c4a9b2ace9a 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -11,6 +11,7 @@
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index bbc3d291e20..ff25f744ded 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -16,12 +16,22 @@ macro_rules! set {
     }};
 }
 
+#[derive(PartialEq)]
+enum FeatureStatus {
+    Default,
+    Incomplete,
+    Internal,
+}
+
 macro_rules! declare_features {
-    (__status_to_bool active) => {
-        false
+    (__status_to_enum active) => {
+        FeatureStatus::Default
     };
-    (__status_to_bool incomplete) => {
-        true
+    (__status_to_enum incomplete) => {
+        FeatureStatus::Incomplete
+    };
+    (__status_to_enum internal) => {
+        FeatureStatus::Internal
     };
     ($(
         $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr, $edition:expr),
@@ -83,7 +93,7 @@ macro_rules! declare_features {
             pub fn incomplete(&self, feature: Symbol) -> bool {
                 match feature {
                     $(
-                        sym::$feature => declare_features!(__status_to_bool $status),
+                        sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Incomplete,
                     )*
                     // accepted and removed features aren't in this file but are never incomplete
                     _ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false,
@@ -91,6 +101,22 @@ macro_rules! declare_features {
                     _ => panic!("`{}` was not listed in `declare_features`", feature),
                 }
             }
+
+            /// Some features are internal to the compiler and standard library and should not
+            /// be used in normal projects. We warn the user about these
+            /// to alert them.
+            pub fn internal(&self, feature: Symbol) -> bool {
+                match feature {
+                    $(
+                        sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Internal,
+                    )*
+                    // accepted and removed features aren't in this file but are never internal
+                    // (a removed feature might have been internal, but it doesn't matter anymore)
+                    _ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false,
+                    _ if self.declared_lib_features.iter().any(|f| f.0 == feature) => false,
+                    _ => panic!("`{}` was not listed in `declare_features`", feature),
+                }
+            }
         }
     };
 }
@@ -137,29 +163,29 @@ declare_features! (
     /// Allows using the `vectorcall` ABI.
     (active, abi_vectorcall, "1.7.0", None, None),
     /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
-    (active, allocator_internals, "1.20.0", None, None),
+    (internal, allocator_internals, "1.20.0", None, None),
     /// Allows using `#[allow_internal_unsafe]`. This is an
     /// attribute on `macro_rules!` and can't use the attribute handling
     /// below (it has to be checked before expansion possibly makes
     /// macros disappear).
-    (active, allow_internal_unsafe, "1.0.0", None, None),
+    (internal, allow_internal_unsafe, "1.0.0", None, None),
     /// Allows using `#[allow_internal_unstable]`. This is an
     /// attribute on `macro_rules!` and can't use the attribute handling
     /// below (it has to be checked before expansion possibly makes
     /// macros disappear).
-    (active, allow_internal_unstable, "1.0.0", None, None),
+    (internal, allow_internal_unstable, "1.0.0", None, None),
     /// Allows using anonymous lifetimes in argument-position impl-trait.
     (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
-    (active, compiler_builtins, "1.13.0", None, None),
+    (internal, compiler_builtins, "1.13.0", None, None),
     /// Allows writing custom MIR
-    (active, custom_mir, "1.65.0", None, None),
+    (internal, custom_mir, "1.65.0", None, None),
     /// Outputs useful `assert!` messages
     (active, generic_assert, "1.63.0", None, None),
     /// Allows using the `rust-intrinsic`'s "ABI".
-    (active, intrinsics, "1.0.0", None, None),
+    (internal, 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),
+    (internal, 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.
@@ -167,22 +193,22 @@ declare_features! (
     /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
     (incomplete, negative_bounds, "1.71.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
-    (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
+    (internal, omit_gdb_pretty_printer_section, "1.5.0", None, None),
     /// Allows using `#[prelude_import]` on glob `use` items.
-    (active, prelude_import, "1.2.0", None, None),
+    (internal, prelude_import, "1.2.0", None, None),
     /// Used to identify crates that contain the profiler runtime.
-    (active, profiler_runtime, "1.18.0", None, None),
+    (internal, profiler_runtime, "1.18.0", None, None),
     /// Allows using `rustc_*` attributes (RFC 572).
-    (active, rustc_attrs, "1.0.0", None, None),
+    (internal, rustc_attrs, "1.0.0", None, None),
     /// Allows using the `#[stable]` and `#[unstable]` attributes.
-    (active, staged_api, "1.0.0", None, None),
+    (internal, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
-    (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    (internal, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
     /// Added for testing unstable lints; perma-unstable.
-    (active, test_unstable_lint, "1.60.0", None, None),
+    (internal, test_unstable_lint, "1.60.0", None, None),
     /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
-    /// Marked `incomplete` since perma-unstable and unsound.
-    (incomplete, unsafe_pin_internals, "1.60.0", None, None),
+    /// Marked `internal` since perma-unstable and unsound.
+    (internal, unsafe_pin_internals, "1.60.0", None, None),
     /// Use for stable + negative coherence and strict coherence depending on trait's
     /// rustc_strict_coherence value.
     (active, with_negative_coherence, "1.60.0", None, None),
@@ -216,19 +242,19 @@ declare_features! (
     /// Allows using the `#[linkage = ".."]` attribute.
     (active, linkage, "1.0.0", Some(29603), None),
     /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed.
-    (active, needs_panic_runtime, "1.10.0", Some(32837), None),
+    (internal, needs_panic_runtime, "1.10.0", Some(32837), None),
     /// Allows using `+bundled,+whole-archive` native libs.
     (active, packed_bundled_libs, "1.69.0", Some(108081), None),
     /// Allows using the `#![panic_runtime]` attribute.
-    (active, panic_runtime, "1.10.0", Some(32837), None),
+    (internal, panic_runtime, "1.10.0", Some(32837), None),
     /// Allows using `#[rustc_allow_const_fn_unstable]`.
     /// This is an attribute on `const fn` for the same
     /// purpose as `#[allow_internal_unstable]`.
-    (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
+    (internal, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
     /// Allows using compiler's own crates.
     (active, rustc_private, "1.0.0", Some(27812), None),
     /// Allows using internal rustdoc features like `doc(keyword)`.
-    (active, rustdoc_internals, "1.58.0", Some(90418), None),
+    (internal, rustdoc_internals, "1.58.0", Some(90418), None),
     /// Allows using the `rustdoc::missing_doc_code_examples` lint
     (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),
     /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 616de57dc63..34214931a08 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -13,6 +13,7 @@
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 064021b1ea4..970efaf312c 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -567,20 +567,6 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         | sym::simd_reduce_min_nanless
         | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
         sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)),
-        name if name.as_str().starts_with("simd_shuffle") => {
-            match name.as_str()["simd_shuffle".len()..].parse() {
-                Ok(n) => {
-                    let params = vec![param(0), param(0), Ty::new_array(tcx, tcx.types.u32, n)];
-                    (2, params, param(1))
-                }
-                Err(_) => {
-                    let msg =
-                        format!("unrecognized platform-specific intrinsic function: `{name}`");
-                    tcx.sess.struct_span_err(it.span, msg).emit();
-                    return;
-                }
-            }
-        }
         _ => {
             let msg = format!("unrecognized platform-specific intrinsic function: `{name}`");
             tcx.sess.struct_span_err(it.span, msg).emit();
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e64848da86b..16d4d099c7e 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -245,13 +245,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         }
         // `ForeignItem`s are handled separately.
         hir::ItemKind::ForeignMod { .. } => {}
-        hir::ItemKind::TyAlias(hir_ty, ..) => {
+        hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
             if tcx.features().lazy_type_alias
                 || tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
             {
                 // Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
                 // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
                 check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
+                check_variances_for_type_defn(tcx, item, ast_generics);
             }
         }
         _ => {}
@@ -1700,10 +1701,27 @@ fn check_variances_for_type_defn<'tcx>(
     hir_generics: &hir::Generics<'_>,
 ) {
     let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
-    for field in tcx.adt_def(item.owner_id).all_fields() {
-        if field.ty(tcx, identity_args).references_error() {
-            return;
+
+    match item.kind {
+        ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
+            for field in tcx.adt_def(item.owner_id).all_fields() {
+                if field.ty(tcx, identity_args).references_error() {
+                    return;
+                }
+            }
+        }
+        ItemKind::TyAlias(..) => {
+            let ty = tcx.type_of(item.owner_id).instantiate_identity();
+
+            if tcx.features().lazy_type_alias || ty.has_opaque_types() {
+                if ty.references_error() {
+                    return;
+                }
+            } else {
+                bug!();
+            }
         }
+        _ => bug!(),
     }
 
     let ty_predicates = tcx.predicates_of(item.owner_id);
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index ec8889781f4..4a3d522e488 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -6,7 +6,7 @@
 use hir::def_id::{DefId, LocalDefId};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
 
 use super::terms::VarianceTerm::*;
@@ -78,6 +78,12 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
                 }
             }
             DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
+            DefKind::TyAlias
+                if tcx.features().lazy_type_alias
+                    || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
+            {
+                constraint_cx.build_constraints_for_item(def_id)
+            }
             _ => {}
         }
     }
@@ -101,7 +107,18 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
 
         let inferred_start = self.terms_cx.inferred_starts[&def_id];
         let current_item = &CurrentItem { inferred_start };
-        match tcx.type_of(def_id).instantiate_identity().kind() {
+        let ty = tcx.type_of(def_id).instantiate_identity();
+
+        // The type as returned by `type_of` is the underlying type and generally not a weak projection.
+        // Therefore we need to check the `DefKind` first.
+        if let DefKind::TyAlias = tcx.def_kind(def_id)
+            && (tcx.features().lazy_type_alias || ty.has_opaque_types())
+        {
+            self.add_constraints_from_ty(current_item, ty, self.covariant);
+            return;
+        }
+
+        match ty.kind() {
             ty::Adt(def, _) => {
                 // Not entirely obvious: constraints on structs/enums do not
                 // affect the variance of their type parameters. See discussion
@@ -127,6 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::Error(_) => {}
+
             _ => {
                 span_bug!(
                     tcx.def_span(def_id),
@@ -252,10 +270,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_args(current, def.did(), args, variance);
             }
 
-            ty::Alias(_, ref data) => {
+            ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, ref data) => {
                 self.add_constraints_from_invariant_args(current, data.args, variance);
             }
 
+            ty::Alias(ty::Weak, ref data) => {
+                self.add_constraints_from_args(current, data.def_id, data.args, variance);
+            }
+
             ty::Dynamic(data, r, _) => {
                 // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
                 self.add_constraints_from_region(current, r, variance);
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 6952a3fa66f..2ef294c6793 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
 use std::ops::ControlFlow;
 
 /// Defines the `TermsContext` basically houses an arena where we can
@@ -56,6 +56,14 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
             let crate_map = tcx.crate_variances(());
             return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
         }
+        DefKind::TyAlias
+            if tcx.features().lazy_type_alias
+                || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
+        {
+            // These are inferred.
+            let crate_map = tcx.crate_variances(());
+            return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
+        }
         DefKind::OpaqueTy => {
             return variance_of_opaque(tcx, item_def_id);
         }
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index ed03c5da26f..1ef3d383bd8 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -12,7 +12,7 @@
 use rustc_arena::DroplessArena;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use std::fmt;
 
 use self::VarianceTerm::*;
@@ -97,6 +97,12 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
                 }
             }
             DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
+            DefKind::TyAlias
+                if tcx.features().lazy_type_alias
+                    || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
+            {
+                terms_cx.add_inferreds_for_item(def_id)
+            }
             _ => {}
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 0700e2e0554..e91103f2130 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -198,13 +198,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     }
 
     /// Like `pat_ty`, but ignores implicit `&` patterns.
+    #[instrument(level = "debug", skip(self), ret)]
     fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
         let base_ty = self.node_ty(pat.hir_id)?;
-        debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty);
+        trace!(?base_ty);
 
         // This code detects whether we are looking at a `ref x`,
         // and if so, figures out what the type *being borrowed* is.
-        let ret_ty = match pat.kind {
+        match pat.kind {
             PatKind::Binding(..) => {
                 let bm = *self
                     .typeck_results
@@ -217,21 +218,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                     // but what we want here is the type of the underlying value being borrowed.
                     // So peel off one-level, turning the &T into T.
                     match base_ty.builtin_deref(false) {
-                        Some(t) => t.ty,
+                        Some(t) => Ok(t.ty),
                         None => {
-                            debug!("By-ref binding of non-derefable type {:?}", base_ty);
-                            return Err(());
+                            debug!("By-ref binding of non-derefable type");
+                            Err(())
                         }
                     }
                 } else {
-                    base_ty
+                    Ok(base_ty)
                 }
             }
-            _ => base_ty,
-        };
-        debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty);
-
-        Ok(ret_ty)
+            _ => Ok(base_ty),
+        }
     }
 
     pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
@@ -299,13 +297,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub(crate) fn cat_expr_unadjusted(
         &self,
         expr: &hir::Expr<'_>,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
-
         let expr_ty = self.expr_ty(expr)?;
         match expr.kind {
             hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
@@ -319,7 +315,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
             hir::ExprKind::Field(ref base, _) => {
                 let base = self.cat_expr(base)?;
-                debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
+                debug!(?base);
 
                 let field_idx = self
                     .typeck_results
@@ -389,7 +385,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip(self, span))]
+    #[instrument(level = "debug", skip(self, span), ret)]
     pub(crate) fn cat_res(
         &self,
         hir_id: hir::HirId,
@@ -430,6 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     /// Note: the actual upvar access contains invisible derefs of closure
     /// environment and upvar reference as appropriate. Only regionck cares
     /// about these dereferences, so we let it compute them as needed.
+    #[instrument(level = "debug", skip(self), ret)]
     fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
         let closure_expr_def_id = self.body_owner;
 
@@ -439,24 +436,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         };
         let var_ty = self.node_ty(var_id)?;
 
-        let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
-
-        debug!("cat_upvar ret={:?}", ret);
-        Ok(ret)
+        Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     pub(crate) fn cat_rvalue(
         &self,
         hir_id: hir::HirId,
         span: Span,
         expr_ty: Ty<'tcx>,
     ) -> PlaceWithHirId<'tcx> {
-        debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
-        let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
-        debug!("cat_rvalue ret={:?}", ret);
-        ret
+        PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
     }
 
+    #[instrument(level = "debug", skip(self, node), ret)]
     pub(crate) fn cat_projection<N: HirNode>(
         &self,
         node: &N,
@@ -464,16 +457,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         ty: Ty<'tcx>,
         kind: ProjectionKind,
     ) -> PlaceWithHirId<'tcx> {
+        let place_ty = base_place.place.ty();
         let mut projections = base_place.place.projections;
+
+        let node_ty = self.typeck_results.node_type(node.hir_id());
+        // Opaque types can't have field projections, but we can instead convert
+        // the current place in-place (heh) to the hidden type, and then apply all
+        // follow up projections on that.
+        if node_ty != place_ty && place_ty.has_opaque_types() {
+            projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
+        }
         projections.push(Projection { kind, ty });
-        let ret = PlaceWithHirId::new(
+        PlaceWithHirId::new(
             node.hir_id(),
             base_place.place.base_ty,
             base_place.place.base,
             projections,
-        );
-        debug!("cat_field ret {:?}", ret);
-        ret
+        )
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -497,7 +497,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.cat_deref(expr, base)
     }
 
-    #[instrument(level = "debug", skip(self, node))]
+    #[instrument(level = "debug", skip(self, node), ret)]
     fn cat_deref(
         &self,
         node: &impl HirNode,
@@ -514,14 +514,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         let mut projections = base_place.place.projections;
         projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
 
-        let ret = PlaceWithHirId::new(
+        Ok(PlaceWithHirId::new(
             node.hir_id(),
             base_place.place.base_ty,
             base_place.place.base,
             projections,
-        );
-        debug!("cat_deref ret {:?}", ret);
-        Ok(ret)
+        ))
     }
 
     pub(crate) fn cat_pattern<F>(
@@ -603,6 +601,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
+    /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
+    /// is being matched against.
+    ///
+    /// In general, the way that this works is that we walk down the pattern,
+    /// constructing a `PlaceWithHirId` that represents the path that will be taken
+    /// to reach the value being matched.
+    #[instrument(skip(self, op), ret, level = "debug")]
     fn cat_pattern_<F>(
         &self,
         mut place_with_id: PlaceWithHirId<'tcx>,
@@ -612,15 +617,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     where
         F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
     {
-        // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
-        // is being matched against.
-        //
-        // In general, the way that this works is that we walk down the pattern,
-        // constructing a `PlaceWithHirId` that represents the path that will be taken
-        // to reach the value being matched.
-
-        debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
-
         // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
         // `PlaceWithHirId`s are constructed differently from patterns. For example, in
         //
@@ -654,11 +650,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
         // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
         for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
-            debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
+            debug!("applying adjustment to place_with_id={:?}", place_with_id);
             place_with_id = self.cat_deref(pat, place_with_id)?;
         }
         let place_with_id = place_with_id; // lose mutability
-        debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
+        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
 
         // Invoke the callback, but only now, after the `place_with_id` has adjusted.
         //
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index be939560c45..1a41786d251 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -264,12 +264,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty);
 
             // If we have an origin, store it.
-            if let Some(origin) = origin {
-                let origin = if enable_precise_capture(span) {
-                    (origin.0, origin.1)
-                } else {
-                    (origin.0, Place { projections: vec![], ..origin.1 })
-                };
+            if let Some(mut origin) = origin {
+                if !enable_precise_capture(span) {
+                    // Without precise captures, we just capture the base and ignore
+                    // the projections.
+                    origin.1.projections.clear()
+                }
 
                 self.typeck_results
                     .borrow_mut()
@@ -294,10 +294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Equate the type variables for the upvars with the actual types.
         let final_upvar_tys = self.final_upvar_tys(closure_def_id);
-        debug!(
-            "analyze_closure: id={:?} args={:?} final_upvar_tys={:?}",
-            closure_hir_id, args, final_upvar_tys
-        );
+        debug!(?closure_hir_id, ?args, ?final_upvar_tys);
 
         // Build a tuple (U0..Un) of the final upvar types U0..Un
         // and unify the upvar tuple type in the closure with it:
@@ -338,10 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let upvar_ty = captured_place.place.ty();
                 let capture = captured_place.info.capture_kind;
 
-                debug!(
-                    "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
-                    captured_place.place, upvar_ty, capture, captured_place.mutability,
-                );
+                debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability);
 
                 apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
             })
@@ -679,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     match (p1.kind, p2.kind) {
                         // Paths are the same, continue to next loop.
                         (ProjectionKind::Deref, ProjectionKind::Deref) => {}
+                        (ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {}
                         (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
                             if i1 == i2 => {}
 
@@ -701,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             l @ (ProjectionKind::Index
                             | ProjectionKind::Subslice
                             | ProjectionKind::Deref
+                            | ProjectionKind::OpaqueCast
                             | ProjectionKind::Field(..)),
                             r @ (ProjectionKind::Index
                             | ProjectionKind::Subslice
                             | ProjectionKind::Deref
+                            | ProjectionKind::OpaqueCast
                             | ProjectionKind::Field(..)),
                         ) => bug!(
                             "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
@@ -1890,6 +1887,7 @@ fn restrict_capture_precision(
                 return (place, curr_mode);
             }
             ProjectionKind::Deref => {}
+            ProjectionKind::OpaqueCast => {}
             ProjectionKind::Field(..) => {} // ignore
         }
     }
@@ -1946,6 +1944,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
             ProjectionKind::Deref => String::from("Deref"),
             ProjectionKind::Index => String::from("Index"),
             ProjectionKind::Subslice => String::from("Subslice"),
+            ProjectionKind::OpaqueCast => String::from("OpaqueCast"),
         };
         if i != 0 {
             projections_str.push(',');
diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs
index 0111a6d302d..8e22ab4083e 100644
--- a/compiler/rustc_incremental/src/assert_module_sources.rs
+++ b/compiler/rustc_incremental/src/assert_module_sources.rs
@@ -6,6 +6,7 @@
 //!
 //! ```
 //! # #![feature(rustc_attrs)]
+//! # #![allow(internal_features)]
 //! #![rustc_partition_reused(module="spike", cfg="rpass2")]
 //! #![rustc_partition_codegened(module="spike-x", cfg="rpass2")]
 //! ```
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index 6fd9f34b29e..9942c70c4ae 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -12,6 +12,7 @@
         test
     )
 )]
+#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))]
 
 #[cfg(feature = "nightly")]
 pub mod bit_set;
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 54d901f20da..9d7a9fefd08 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -562,15 +562,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
         let needs_canonical_flags = if canonicalize_region_mode.any() {
-            TypeFlags::HAS_INFER |
-            TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
-            TypeFlags::HAS_TY_PLACEHOLDER |
-            TypeFlags::HAS_CT_PLACEHOLDER
+            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS
         } else {
-            TypeFlags::HAS_INFER
-                | TypeFlags::HAS_RE_PLACEHOLDER
-                | TypeFlags::HAS_TY_PLACEHOLDER
-                | TypeFlags::HAS_CT_PLACEHOLDER
+            TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER
         };
 
         // Fast path: nothing that needs to be canonicalized.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 25077f9bb97..7739cf1ee05 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -764,7 +764,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             Some(ty) if expected == ty => {
                                 let source_map = self.tcx.sess.source_map();
                                 err.span_suggestion(
-                                    source_map.end_point(cause.span),
+                                    source_map.end_point(cause.span()),
                                     "try removing this `?`",
                                     "",
                                     Applicability::MachineApplicable,
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index f482e3d7c12..1b4c8ce120a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -72,6 +72,9 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n
     .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
     .help = consider using `min_{$name}` instead, which is more stable and complete
 
+lint_builtin_internal_features = the feature `{$name}` is internal to the compiler or standard library
+    .note = using it is strongly discouraged
+
 lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition
     .suggestion = you can use a raw identifier to stay compatible
 
@@ -213,9 +216,6 @@ lint_expectation = this lint expectation is unfulfilled
     .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
     .rationale = {$rationale}
 
-lint_fn_null_check = function pointers are not nullable, so checking them for null will always return false
-    .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
 lint_for_loops_over_fallibles =
     for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
     .suggestion = consider using `if let` to clear intent
@@ -454,6 +454,13 @@ lint_path_statement_drop = path statement drops value
 
 lint_path_statement_no_effect = path statement with no effect
 
+lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false
+    .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+    .label = expression has type `{$orig_ty}`
+
+lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
+    .label = expression has type `{$orig_ty}`
+
 lint_query_instability = using `{$query}` can result in unstable query results
     .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index e6917f4b2d3..cc6d5330c33 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -28,8 +28,8 @@ use crate::{
         BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
         BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
         BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
-        BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures,
-        BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents,
+        BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
+        BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
         BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
         BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
         BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
@@ -2301,12 +2301,36 @@ declare_lint! {
     "incomplete features that may function improperly in some or all cases"
 }
 
+declare_lint! {
+    /// The `internal_features` lint detects unstable features enabled with
+    /// the [`feature` attribute] that are internal to the compiler or standard
+    /// library.
+    ///
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(rustc_attrs)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// These features are an implementation detail of the compiler and standard
+    /// library and are not supposed to be used in user code.
+    pub INTERNAL_FEATURES,
+    Deny,
+    "internal features are not supposed to be used"
+}
+
 declare_lint_pass!(
     /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
-    IncompleteFeatures => [INCOMPLETE_FEATURES]
+    IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES]
 );
 
-impl EarlyLintPass for IncompleteFeatures {
+impl EarlyLintPass for IncompleteInternalFeatures {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
         let features = cx.sess().features_untracked();
         features
@@ -2314,17 +2338,26 @@ impl EarlyLintPass for IncompleteFeatures {
             .iter()
             .map(|(name, span, _)| (name, span))
             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
-            .filter(|(&name, _)| features.incomplete(name))
+            .filter(|(&name, _)| features.incomplete(name) || features.internal(name))
             .for_each(|(&name, &span)| {
                 let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
-                    .map(|n| BuiltinIncompleteFeaturesNote { n });
-                let help =
-                    HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
-                cx.emit_spanned_lint(
-                    INCOMPLETE_FEATURES,
-                    span,
-                    BuiltinIncompleteFeatures { name, note, help },
-                );
+                    .map(|n| BuiltinFeatureIssueNote { n });
+
+                if features.incomplete(name) {
+                    let help =
+                        HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
+                    cx.emit_spanned_lint(
+                        INCOMPLETE_FEATURES,
+                        span,
+                        BuiltinIncompleteFeatures { name, note, help },
+                    );
+                } else {
+                    cx.emit_spanned_lint(
+                        INTERNAL_FEATURES,
+                        span,
+                        BuiltinInternalFeatures { name, note },
+                    );
+                }
             });
     }
 }
diff --git a/compiler/rustc_lint/src/fn_null_check.rs b/compiler/rustc_lint/src/fn_null_check.rs
deleted file mode 100644
index e3b33463ccf..00000000000
--- a/compiler/rustc_lint/src/fn_null_check.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use crate::{lints::FnNullCheckDiag, LateContext, LateLintPass, LintContext};
-use rustc_ast::LitKind;
-use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::sym;
-
-declare_lint! {
-    /// The `incorrect_fn_null_checks` lint checks for expression that checks if a
-    /// function pointer is null.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// # fn test() {}
-    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
-    /// #   test;
-    ///
-    /// if (fn_ptr as *const ()).is_null() { /* ... */ }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Function pointers are assumed to be non-null, checking them for null will always
-    /// return false.
-    INCORRECT_FN_NULL_CHECKS,
-    Warn,
-    "incorrect checking of null function pointer"
-}
-
-declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]);
-
-fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let mut expr = expr.peel_blocks();
-    let mut had_at_least_one_cast = false;
-    while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
-            && let TyKind::Ptr(_) = cast_ty.kind {
-        expr = cast_expr.peel_blocks();
-        had_at_least_one_cast = true;
-    }
-    had_at_least_one_cast && cx.typeck_results().expr_ty_adjusted(expr).is_fn()
-}
-
-impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        match expr.kind {
-            // Catching:
-            // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
-            ExprKind::Call(path, [arg])
-                if let ExprKind::Path(ref qpath) = path.kind
-                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-                    && matches!(
-                        cx.tcx.get_diagnostic_name(def_id),
-                        Some(sym::ptr_const_is_null | sym::ptr_is_null)
-                    )
-                    && is_fn_ptr_cast(cx, arg) =>
-            {
-                cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-            }
-
-            // Catching:
-            // (fn_ptr as *<const/mut> <ty>).is_null()
-            ExprKind::MethodCall(_, receiver, _, _)
-                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-                    && matches!(
-                        cx.tcx.get_diagnostic_name(def_id),
-                        Some(sym::ptr_const_is_null | sym::ptr_is_null)
-                    )
-                    && is_fn_ptr_cast(cx, receiver) =>
-            {
-                cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-            }
-
-            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
-                let to_check: &Expr<'_>;
-                if is_fn_ptr_cast(cx, left) {
-                    to_check = right;
-                } else if is_fn_ptr_cast(cx, right) {
-                    to_check = left;
-                } else {
-                    return;
-                }
-
-                match to_check.kind {
-                    // Catching:
-                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
-                    ExprKind::Cast(cast_expr, _)
-                        if let ExprKind::Lit(spanned) = cast_expr.kind
-                            && let LitKind::Int(v, _) = spanned.node && v == 0 =>
-                    {
-                        cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-                    },
-
-                    // Catching:
-                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
-                    ExprKind::Call(path, [])
-                        if let ExprKind::Path(ref qpath) = path.kind
-                            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-                            && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
-                            && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
-                    {
-                        cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
-                    },
-
-                    _ => {},
-                }
-            }
-            _ => {}
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 96fd3ccf774..9bd442e64e3 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -40,6 +40,7 @@
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_middle;
@@ -57,7 +58,6 @@ mod early;
 mod enum_intrinsics_non_enums;
 mod errors;
 mod expect;
-mod fn_null_check;
 mod for_loops_over_fallibles;
 pub mod hidden_unicode_codepoints;
 mod internal;
@@ -76,6 +76,7 @@ mod noop_method_call;
 mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
+mod ptr_nulls;
 mod redundant_semicolon;
 mod reference_casting;
 mod traits;
@@ -102,7 +103,6 @@ use builtin::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
-use fn_null_check::*;
 use for_loops_over_fallibles::*;
 use hidden_unicode_codepoints::*;
 use internal::*;
@@ -117,6 +117,7 @@ use nonstandard_style::*;
 use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
+use ptr_nulls::*;
 use redundant_semicolon::*;
 use reference_casting::*;
 use traits::*;
@@ -173,7 +174,7 @@ early_lint_methods!(
             WhileTrue: WhileTrue,
             NonAsciiIdents: NonAsciiIdents,
             HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
-            IncompleteFeatures: IncompleteFeatures,
+            IncompleteInternalFeatures: IncompleteInternalFeatures,
             RedundantSemicolons: RedundantSemicolons,
             UnusedDocComment: UnusedDocComment,
             UnexpectedCfgs: UnexpectedCfgs,
@@ -227,7 +228,7 @@ late_lint_methods!(
             // Depends on types used in type definitions
             MissingCopyImplementations: MissingCopyImplementations,
             // Depends on referenced function signatures in expressions
-            IncorrectFnNullChecks: IncorrectFnNullChecks,
+            PtrNullChecks: PtrNullChecks,
             MutableTransmutes: MutableTransmutes,
             TypeAliasBounds: TypeAliasBounds,
             TrivialConstraints: TrivialConstraints,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index a6a48bf4ffa..604daf2e90a 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -405,18 +405,27 @@ pub struct BuiltinExplicitOutlivesSuggestion {
 pub struct BuiltinIncompleteFeatures {
     pub name: Symbol,
     #[subdiagnostic]
-    pub note: Option<BuiltinIncompleteFeaturesNote>,
+    pub note: Option<BuiltinFeatureIssueNote>,
     #[subdiagnostic]
     pub help: Option<BuiltinIncompleteFeaturesHelp>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_internal_features)]
+#[note]
+pub struct BuiltinInternalFeatures {
+    pub name: Symbol,
+    #[subdiagnostic]
+    pub note: Option<BuiltinFeatureIssueNote>,
+}
+
 #[derive(Subdiagnostic)]
 #[help(lint_help)]
 pub struct BuiltinIncompleteFeaturesHelp;
 
 #[derive(Subdiagnostic)]
 #[note(lint_note)]
-pub struct BuiltinIncompleteFeaturesNote {
+pub struct BuiltinFeatureIssueNote {
     pub n: NonZeroU32,
 }
 
@@ -613,11 +622,23 @@ pub struct ExpectationNote {
     pub rationale: Symbol,
 }
 
-// fn_null_check.rs
+// ptr_nulls.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_fn_null_check)]
-#[help]
-pub struct FnNullCheckDiag;
+pub enum PtrNullChecksDiag<'a> {
+    #[diag(lint_ptr_null_checks_fn_ptr)]
+    #[help(lint_help)]
+    FnPtr {
+        orig_ty: Ty<'a>,
+        #[label]
+        label: Span,
+    },
+    #[diag(lint_ptr_null_checks_ref)]
+    Ref {
+        orig_ty: Ty<'a>,
+        #[label]
+        label: Span,
+    },
+}
 
 // for_loops_over_fallibles.rs
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
new file mode 100644
index 00000000000..02aff91032f
--- /dev/null
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -0,0 +1,146 @@
+use crate::{lints::PtrNullChecksDiag, LateContext, LateLintPass, LintContext};
+use rustc_ast::LitKind;
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+declare_lint! {
+    /// The `useless_ptr_null_checks` lint checks for useless null checks against pointers
+    /// obtained from non-null types.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # fn test() {}
+    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+    /// #   test;
+    ///
+    /// if (fn_ptr as *const ()).is_null() { /* ... */ }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Function pointers and references are assumed to be non-null, checking them for null
+    /// will always return false.
+    USELESS_PTR_NULL_CHECKS,
+    Warn,
+    "useless checking of non-null-typed pointer"
+}
+
+declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
+
+/// This function detects and returns the original expression from a series of consecutive casts,
+/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
+fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
+    let mut had_at_least_one_cast = false;
+    loop {
+        e = e.peel_blocks();
+        e = if let ExprKind::Cast(expr, t) = e.kind
+            && let TyKind::Ptr(_) = t.kind {
+            had_at_least_one_cast = true;
+            expr
+        } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
+            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+            && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
+            had_at_least_one_cast = true;
+            expr
+        } else if let ExprKind::Call(path, [arg]) = e.kind
+            && let ExprKind::Path(ref qpath) = path.kind
+            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+            && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) {
+            had_at_least_one_cast = true;
+            arg
+        } else if had_at_least_one_cast {
+            return Some(e);
+        } else {
+            return None;
+        };
+    }
+}
+
+fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
+    let expr = ptr_cast_chain(cx, expr)?;
+
+    let orig_ty = cx.typeck_results().expr_ty(expr);
+    if orig_ty.is_fn() {
+        Some(PtrNullChecksDiag::FnPtr { orig_ty, label: expr.span })
+    } else if orig_ty.is_ref() {
+        Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
+    } else {
+        None
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        match expr.kind {
+            // Catching:
+            // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
+            ExprKind::Call(path, [arg])
+                if let ExprKind::Path(ref qpath) = path.kind
+                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                    && matches!(
+                        cx.tcx.get_diagnostic_name(def_id),
+                        Some(sym::ptr_const_is_null | sym::ptr_is_null)
+                    )
+                    && let Some(diag) = incorrect_check(cx, arg) =>
+            {
+                cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+            }
+
+            // Catching:
+            // (fn_ptr as *<const/mut> <ty>).is_null()
+            ExprKind::MethodCall(_, receiver, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && matches!(
+                        cx.tcx.get_diagnostic_name(def_id),
+                        Some(sym::ptr_const_is_null | sym::ptr_is_null)
+                    )
+                    && let Some(diag) = incorrect_check(cx, receiver) =>
+            {
+                cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+            }
+
+            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+                let to_check: &Expr<'_>;
+                let diag: PtrNullChecksDiag<'_>;
+                if let Some(ddiag) = incorrect_check(cx, left) {
+                    to_check = right;
+                    diag = ddiag;
+                } else if let Some(ddiag) = incorrect_check(cx, right) {
+                    to_check = left;
+                    diag = ddiag;
+                } else {
+                    return;
+                }
+
+                match to_check.kind {
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
+                    ExprKind::Cast(cast_expr, _)
+                        if let ExprKind::Lit(spanned) = cast_expr.kind
+                            && let LitKind::Int(v, _) = spanned.node && v == 0 =>
+                    {
+                        cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
+                    ExprKind::Call(path, [])
+                        if let ExprKind::Path(ref qpath) = path.kind
+                            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                            && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
+                            && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
+                    {
+                        cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
+                    },
+
+                    _ => {},
+                }
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 7e3b6e9e218..1a612731808 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3925,7 +3925,6 @@ declare_lint! {
     ///
     /// // in crate B
     /// #![feature(non_exhaustive_omitted_patterns_lint)]
-    ///
     /// match Bar::A {
     ///     Bar::A => {},
     ///     #[warn(non_exhaustive_omitted_patterns)]
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 904f8eb5731..f4593d0fe73 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -7,6 +7,7 @@
 #![allow(rustc::default_hash_types)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![recursion_limit = "128"]
 
 use synstructure::decl_derive;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d72053ca985..f12094a271f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -30,6 +30,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@@ -1034,7 +1035,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
     }
 }
 
-fn should_encode_variances(def_kind: DefKind) -> bool {
+fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool {
     match def_kind {
         DefKind::Struct
         | DefKind::Union
@@ -1053,7 +1054,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::Static(..)
         | DefKind::Const
         | DefKind::ForeignMod
-        | DefKind::TyAlias
         | DefKind::Impl { .. }
         | DefKind::Trait
         | DefKind::TraitAlias
@@ -1067,6 +1067,10 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::Closure
         | DefKind::Generator
         | DefKind::ExternCrate => false,
+        DefKind::TyAlias => {
+            tcx.features().lazy_type_alias
+                || tcx.type_of(def_id).instantiate_identity().has_opaque_types()
+        }
     }
 }
 
@@ -1349,7 +1353,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.encode_default_body_stability(def_id);
                 self.encode_deprecation(def_id);
             }
-            if should_encode_variances(def_kind) {
+            if should_encode_variances(tcx, def_id, def_kind) {
                 let v = self.tcx.variances_of(def_id);
                 record_array!(self.tables.variances_of[def_id] <- v);
             }
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 8a22de931c3..32f3a177508 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -36,6 +36,10 @@ pub enum ProjectionKind {
 
     /// A subslice covering a range of values like `B[x..y]`.
     Subslice,
+
+    /// A conversion from an opaque type to its hidden type so we can
+    /// do further projections on it.
+    OpaqueCast,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 1b125e8e26d..f5576b59571 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -64,6 +64,7 @@
 #![feature(macro_metavar_expr)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate bitflags;
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index c1cb2f2e497..2567170f39a 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -18,9 +18,9 @@ use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
 use super::{
-    read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance,
-    ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess,
-    UnsupportedOpInfo,
+    read_target_uint, write_target_uint, AllocId, BadBytesAccess, InterpError, InterpResult,
+    Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch,
+    UndefinedBehaviorInfo, UnsupportedOpInfo,
 };
 use crate::ty;
 use init_mask::*;
@@ -173,13 +173,13 @@ pub enum AllocError {
     /// A scalar had the wrong size.
     ScalarSizeMismatch(ScalarSizeMismatch),
     /// Encountered a pointer where we needed raw bytes.
-    ReadPointerAsBytes,
+    ReadPointerAsInt(Option<BadBytesAccess>),
     /// Partially overwriting a pointer.
-    PartialPointerOverwrite(Size),
+    OverwritePartialPointer(Size),
     /// Partially copying a pointer.
-    PartialPointerCopy(Size),
+    ReadPartialPointer(Size),
     /// Using uninitialized data where it is not allowed.
-    InvalidUninitBytes(Option<UninitBytesAccess>),
+    InvalidUninitBytes(Option<BadBytesAccess>),
 }
 pub type AllocResult<T = ()> = Result<T, AllocError>;
 
@@ -196,12 +196,14 @@ impl AllocError {
             ScalarSizeMismatch(s) => {
                 InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
             }
-            ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes),
-            PartialPointerOverwrite(offset) => InterpError::Unsupported(
-                UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)),
+            ReadPointerAsInt(info) => InterpError::Unsupported(
+                UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))),
             ),
-            PartialPointerCopy(offset) => InterpError::Unsupported(
-                UnsupportedOpInfo::PartialPointerCopy(Pointer::new(alloc_id, offset)),
+            OverwritePartialPointer(offset) => InterpError::Unsupported(
+                UnsupportedOpInfo::OverwritePartialPointer(Pointer::new(alloc_id, offset)),
+            ),
+            ReadPartialPointer(offset) => InterpError::Unsupported(
+                UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)),
             ),
             InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
                 UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
@@ -433,14 +435,26 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         range: AllocRange,
     ) -> AllocResult<&[u8]> {
         self.init_mask.is_range_initialized(range).map_err(|uninit_range| {
-            AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+            AllocError::InvalidUninitBytes(Some(BadBytesAccess {
                 access: range,
-                uninit: uninit_range,
+                bad: uninit_range,
             }))
         })?;
         if !Prov::OFFSET_IS_ADDR {
             if !self.provenance.range_empty(range, cx) {
-                return Err(AllocError::ReadPointerAsBytes);
+                // Find the provenance.
+                let (offset, _prov) = self
+                    .provenance
+                    .range_get_ptrs(range, cx)
+                    .first()
+                    .copied()
+                    .expect("there must be provenance somewhere here");
+                let start = offset.max(range.start); // the pointer might begin before `range`!
+                let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`!
+                return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess {
+                    access: range,
+                    bad: AllocRange::from(start..end),
+                })));
             }
         }
         Ok(self.get_bytes_unchecked(range))
@@ -536,23 +550,25 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
                 // Now use this provenance.
                 let ptr = Pointer::new(prov, Size::from_bytes(bits));
                 return Ok(Scalar::from_maybe_pointer(ptr, cx));
+            } else {
+                // Without OFFSET_IS_ADDR, the only remaining case we can handle is total absence of
+                // provenance.
+                if self.provenance.range_empty(range, cx) {
+                    return Ok(Scalar::from_uint(bits, range.size));
+                }
+                // Else we have mixed provenance, that doesn't work.
+                return Err(AllocError::ReadPartialPointer(range.start));
             }
         } else {
             // We are *not* reading a pointer.
-            // If we can just ignore provenance, do exactly that.
-            if Prov::OFFSET_IS_ADDR {
+            // If we can just ignore provenance or there is none, that's easy.
+            if Prov::OFFSET_IS_ADDR || self.provenance.range_empty(range, cx) {
                 // We just strip provenance.
                 return Ok(Scalar::from_uint(bits, range.size));
             }
+            // There is some provenance and we don't have OFFSET_IS_ADDR. This doesn't work.
+            return Err(AllocError::ReadPointerAsInt(None));
         }
-
-        // Fallback path for when we cannot treat provenance bytewise or ignore it.
-        assert!(!Prov::OFFSET_IS_ADDR);
-        if !self.provenance.range_empty(range, cx) {
-            return Err(AllocError::ReadPointerAsBytes);
-        }
-        // There is no provenance, we can just return the bits.
-        Ok(Scalar::from_uint(bits, range.size))
     }
 
     /// Writes a *non-ZST* scalar.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index 318f93e12b5..0243fc4513a 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -66,7 +66,11 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
     /// Returns all ptr-sized provenance in the given range.
     /// If the range has length 0, returns provenance that crosses the edge between `start-1` and
     /// `start`.
-    fn range_get_ptrs(&self, range: AllocRange, cx: &impl HasDataLayout) -> &[(Size, Prov)] {
+    pub(super) fn range_get_ptrs(
+        &self,
+        range: AllocRange,
+        cx: &impl HasDataLayout,
+    ) -> &[(Size, Prov)] {
         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
         // the beginning of this range.
         let adjusted_start = Size::from_bytes(
@@ -158,7 +162,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         if first < start {
             if !Prov::OFFSET_IS_ADDR {
                 // We can't split up the provenance into less than a pointer.
-                return Err(AllocError::PartialPointerOverwrite(first));
+                return Err(AllocError::OverwritePartialPointer(first));
             }
             // Insert the remaining part in the bytewise provenance.
             let prov = self.ptrs[&first];
@@ -171,7 +175,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
             let begin_of_last = last - cx.data_layout().pointer_size;
             if !Prov::OFFSET_IS_ADDR {
                 // We can't split up the provenance into less than a pointer.
-                return Err(AllocError::PartialPointerOverwrite(begin_of_last));
+                return Err(AllocError::OverwritePartialPointer(begin_of_last));
             }
             // Insert the remaining part in the bytewise provenance.
             let prov = self.ptrs[&begin_of_last];
@@ -246,10 +250,10 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         if !Prov::OFFSET_IS_ADDR {
             // There can't be any bytewise provenance, and we cannot split up the begin/end overlap.
             if let Some(entry) = begin_overlap {
-                return Err(AllocError::PartialPointerCopy(entry.0));
+                return Err(AllocError::ReadPartialPointer(entry.0));
             }
             if let Some(entry) = end_overlap {
-                return Err(AllocError::PartialPointerCopy(entry.0));
+                return Err(AllocError::ReadPartialPointer(entry.0));
             }
             debug_assert!(self.bytes.is_none());
         } else {
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 65652b10afb..2e46bfc1a38 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -134,10 +134,6 @@ impl InterpErrorBacktrace {
 }
 
 impl<'tcx> InterpErrorInfo<'tcx> {
-    pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self {
-        Self(Box::new(InterpErrorInfoInner { kind, backtrace }))
-    }
-
     pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) {
         let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self;
         (kind, backtrace)
@@ -226,13 +222,13 @@ impl IntoDiagnosticArg for InvalidMetaKind {
     }
 }
 
-/// Details of an access to uninitialized bytes where it is not allowed.
+/// Details of an access to uninitialized bytes / bad pointer bytes where it is not allowed.
 #[derive(Debug, Clone, Copy)]
-pub struct UninitBytesAccess {
+pub struct BadBytesAccess {
     /// Range of the original memory access.
     pub access: AllocRange,
-    /// Range of the uninit memory that was encountered. (Might not be maximal.)
-    pub uninit: AllocRange,
+    /// Range of the bad memory that was encountered. (Might not be maximal.)
+    pub bad: AllocRange,
 }
 
 /// Information about a size mismatch.
@@ -316,7 +312,7 @@ pub enum UndefinedBehaviorInfo<'a> {
     /// Using a string that is not valid UTF-8,
     InvalidStr(std::str::Utf8Error),
     /// Using uninitialized data where it is not allowed.
-    InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>),
+    InvalidUninitBytes(Option<(AllocId, BadBytesAccess)>),
     /// Working with a local that is not currently live.
     DeadLocal,
     /// Data size is not equal to target size.
@@ -326,7 +322,7 @@ pub enum UndefinedBehaviorInfo<'a> {
     /// An uninhabited enum variant is projected.
     UninhabitedEnumVariantRead(VariantIdx),
     /// Validation error.
-    Validation(ValidationErrorInfo<'a>),
+    ValidationError(ValidationErrorInfo<'a>),
     // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
     // dispatched
     /// A custom (free-form) error, created by `err_ub_custom!`.
@@ -368,6 +364,8 @@ pub enum ExpectedKind {
     Float,
     Int,
     FnPtr,
+    EnumTag,
+    Str,
 }
 
 impl From<PointerKind> for ExpectedKind {
@@ -381,10 +379,11 @@ impl From<PointerKind> for ExpectedKind {
 
 #[derive(Debug)]
 pub enum ValidationErrorKind<'tcx> {
+    PointerAsInt { expected: ExpectedKind },
+    PartialPointer,
     PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
     PtrToStatic { ptr_kind: PointerKind },
     PtrToMut { ptr_kind: PointerKind },
-    ExpectedNonPtr { value: String },
     MutableRefInConst,
     NullFnPtr,
     NeverVal,
@@ -394,11 +393,8 @@ pub enum ValidationErrorKind<'tcx> {
     UnsafeCell,
     UninhabitedVal { ty: Ty<'tcx> },
     InvalidEnumTag { value: String },
-    UninhabitedEnumTag,
-    UninitEnumTag,
-    UninitStr,
+    UninhabitedEnumVariant,
     Uninit { expected: ExpectedKind },
-    UninitVal,
     InvalidVTablePtr { value: String },
     InvalidMetaSliceTooLarge { ptr_kind: PointerKind },
     InvalidMetaTooLarge { ptr_kind: PointerKind },
@@ -426,12 +422,12 @@ pub enum UnsupportedOpInfo {
     //
     /// Overwriting parts of a pointer; without knowing absolute addresses, the resulting state
     /// cannot be represented by the CTFE interpreter.
-    PartialPointerOverwrite(Pointer<AllocId>),
-    /// Attempting to `copy` parts of a pointer to somewhere else; without knowing absolute
+    OverwritePartialPointer(Pointer<AllocId>),
+    /// Attempting to read or copy parts of a pointer to somewhere else; without knowing absolute
     /// addresses, the resulting state cannot be represented by the CTFE interpreter.
-    PartialPointerCopy(Pointer<AllocId>),
-    /// Encountered a pointer where we needed raw bytes.
-    ReadPointerAsBytes,
+    ReadPartialPointer(Pointer<AllocId>),
+    /// Encountered a pointer where we needed an integer.
+    ReadPointerAsInt(Option<(AllocId, BadBytesAccess)>),
     /// Accessing thread local statics
     ThreadLocalStatic(DefId),
     /// Accessing an unsupported extern static.
@@ -497,7 +493,7 @@ impl InterpError<'_> {
         matches!(
             self,
             InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
-                | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Validation { .. })
+                | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. })
                 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
         )
     }
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b35ba9503db..3543158bf82 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -142,11 +142,11 @@ use crate::ty::GenericArgKind;
 use crate::ty::{self, Instance, Ty, TyCtxt};
 
 pub use self::error::{
-    struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
-    EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind,
-    InvalidProgramInfo, MachineStopType, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
-    ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
-    ValidationErrorInfo, ValidationErrorKind,
+    struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult,
+    EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo,
+    InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, PointerKind,
+    ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
+    UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
 };
 
 pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 20861d5ffa4..5345a658803 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -378,15 +378,16 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     #[inline]
     pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
-        self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err(
-            |size| {
+        self.try_to_int()
+            .map_err(|_| err_unsup!(ReadPointerAsInt(None)))?
+            .to_bits(target_size)
+            .map_err(|size| {
                 err_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
                     target_size: target_size.bytes(),
                     data_size: size.bytes(),
                 }))
                 .into()
-            },
-        )
+            })
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1189dcdfcbb..a02f9a9f796 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -749,7 +749,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Gets a map with the variance of every item; use `item_variance` instead.
+    /// Gets a map with the variance of every item; use `variances_of` instead.
     query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
         arena_cache
         desc { "computing the variances for items in this crate" }
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index b21a00e4122..90139f925ed 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -147,7 +147,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
 }
 
 /// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)]
 pub struct ExternalConstraintsData<'tcx> {
     // FIXME: implement this.
     pub region_constraints: QueryRegionConstraints<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 42f22604975..2e5c6a44579 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -174,6 +174,8 @@ impl<'tcx> CapturedPlace<'tcx> {
                 // Ignore derefs for now, as they are likely caused by
                 // autoderefs that don't appear in the original code.
                 HirProjectionKind::Deref => {}
+                // Just change the type to the hidden type, so we can actually project.
+                HirProjectionKind::OpaqueCast => {}
                 proj => bug!("Unexpected projection {:?} in captured place", proj),
             }
             ty = proj.ty;
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 520bb55e031..156eda477ad 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -88,14 +88,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
         self.has_type_flags(TypeFlags::HAS_INFER)
     }
     fn has_placeholders(&self) -> bool {
-        self.has_type_flags(
-            TypeFlags::HAS_RE_PLACEHOLDER
-                | TypeFlags::HAS_TY_PLACEHOLDER
-                | TypeFlags::HAS_CT_PLACEHOLDER,
-        )
+        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
     }
     fn has_non_region_placeholders(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
+        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
     }
     fn has_param(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_PARAM)
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 7756d5d4879..2e7ef265a93 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -236,6 +236,9 @@ fn strip_prefix<'a, 'tcx>(
                 }
                 assert_matches!(iter.next(), Some(ProjectionElem::Field(..)));
             }
+            HirProjectionKind::OpaqueCast => {
+                assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..)));
+            }
             HirProjectionKind::Index | HirProjectionKind::Subslice => {
                 bug!("unexpected projection kind: {:?}", projection);
             }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index ff4620948fa..b907b69224c 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1072,6 +1072,9 @@ impl<'tcx> Cx<'tcx> {
                     variant_index,
                     name: field,
                 },
+                HirProjectionKind::OpaqueCast => {
+                    ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
+                }
                 HirProjectionKind::Index | HirProjectionKind::Subslice => {
                     // We don't capture these projections, so we can ignore them here
                     continue;
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f13c8214af1..fc9e18378d5 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -223,19 +223,29 @@ impl<'tcx> Inliner<'tcx> {
             return Err("failed to normalize return type");
         }
         if callsite.fn_sig.abi() == Abi::RustCall {
-            let (arg_tuple, skipped_args) = match &args[..] {
-                [arg_tuple] => (arg_tuple, 0),
-                [_, arg_tuple] => (arg_tuple, 1),
+            // FIXME: Don't inline user-written `extern "rust-call"` functions,
+            // since this is generally perf-negative on rustc, and we hope that
+            // LLVM will inline these functions instead.
+            if callee_body.spread_arg.is_some() {
+                return Err("do not inline user-written rust-call functions");
+            }
+
+            let (self_arg, arg_tuple) = match &args[..] {
+                [arg_tuple] => (None, arg_tuple),
+                [self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
                 _ => bug!("Expected `rust-call` to have 1 or 2 args"),
             };
 
+            let self_arg_ty =
+                self_arg.map(|self_arg| self_arg.ty(&caller_body.local_decls, self.tcx));
+
             let arg_tuple_ty = arg_tuple.ty(&caller_body.local_decls, self.tcx);
-            let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else {
+            let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
                 bug!("Closure arguments are not passed as a tuple");
             };
 
             for (arg_ty, input) in
-                arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args))
+                self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
             {
                 let input_type = callee_body.local_decls[input].ty;
                 if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index d1ecfe9f851..fc36c6e4124 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -305,7 +305,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             terminator.kind = TerminatorKind::Unreachable;
                         }
                     }
-                    _ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
+                    sym::simd_shuffle => {
                         validate_simd_shuffle(tcx, args, terminator.source_info.span);
                     }
                     _ => {}
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 83d96ad8e76..6888127f36c 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -23,6 +23,8 @@ parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or late
 parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
     .label = to use `async fn`, switch to Rust 2018 or later
 
+parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later
+
 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
     .suggestion = try switching the order
 
@@ -270,6 +272,8 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
 parse_function_body_equals_expr = function body cannot be `= expression;`
     .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
 
+parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax
+
 parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
     .suggestion = surround the type parameters with angle brackets
 
@@ -457,6 +461,12 @@ parse_loop_else = `{$loop_kind}...else` loops are not supported
     .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
     .loop_keyword = `else` is attached to this loop
 
+parse_macro_expands_to_adt_field = macros cannot expand to {$adt_ty} fields
+
+parse_macro_expands_to_enum_variant = macros cannot expand to enum variants
+
+parse_macro_expands_to_match_arm = macros cannot expand to match arms
+
 parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
     .suggestion = remove the visibility
     .help = try adjusting the macro to put `{$vis}` inside the invocation
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 06c09960727..26f38c9156a 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1435,6 +1435,13 @@ pub(crate) struct AsyncBlockIn2015 {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_async_move_block_in_2015)]
+pub(crate) struct AsyncMoveBlockIn2015 {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_self_argument_pointer)]
 pub(crate) struct SelfArgumentPointer {
     #[primary_span]
@@ -1809,6 +1816,12 @@ pub struct UnknownPrefix<'a> {
 }
 
 #[derive(Subdiagnostic)]
+#[note(parse_macro_expands_to_adt_field)]
+pub struct MacroExpandsToAdtField<'a> {
+    pub adt_ty: &'a str,
+}
+
+#[derive(Subdiagnostic)]
 pub enum UnknownPrefixSugg {
     #[suggestion(
         parse_suggestion_br,
@@ -2731,3 +2744,17 @@ pub(crate) struct WhereClauseBeforeConstBodySugg {
     #[suggestion_part(code = "")]
     pub right: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(parse_generic_args_in_pat_require_turbofish_syntax)]
+pub(crate) struct GenericArgsInPatRequireTurbofishSyntax {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(
+        parse_sugg_turbofish_syntax,
+        style = "verbose",
+        code = "::",
+        applicability = "maybe-incorrect"
+    )]
+    pub suggest_turbofish: Span,
+}
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 6712db26693..892be36aae7 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -8,6 +8,7 @@
 #![feature(never_type)]
 #![feature(rustc_attrs)]
 #![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index e6de51a673c..4e639a54cf7 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -4,10 +4,11 @@ use super::{
     TokenExpectType, TokenType,
 };
 use crate::errors::{
-    AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
-    ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
-    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
-    DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+    AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus,
+    BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
+    ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
+    ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
+    DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
     GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
     HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
     IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
@@ -573,6 +574,12 @@ impl<'a> Parser<'a> {
             return Err(self.sess.create_err(UseEqInstead { span: self.token.span }));
         }
 
+        if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
+            // The 2015 edition is in use because parsing of `async move` has failed.
+            let span = self.prev_token.span.to(self.token.span);
+            return Err(self.sess.create_err(AsyncMoveBlockIn2015 { span }));
+        }
+
         let expect = tokens_to_string(&expected);
         let actual = super::token_descr(&self.token);
         let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -2100,7 +2107,7 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
-        let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName))?;
+        let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
@@ -2508,7 +2515,7 @@ impl<'a> Parser<'a> {
                 // Skip the `:`.
                 snapshot_pat.bump();
                 snapshot_type.bump();
-                match snapshot_pat.parse_pat_no_top_alt(expected) {
+                match snapshot_pat.parse_pat_no_top_alt(expected, None) {
                     Err(inner_err) => {
                         inner_err.cancel();
                     }
@@ -2634,6 +2641,7 @@ impl<'a> Parser<'a> {
     pub(crate) fn maybe_recover_unexpected_comma(
         &mut self,
         lo: Span,
+        is_mac_invoc: bool,
         rt: CommaRecoveryMode,
     ) -> PResult<'a, ()> {
         if self.token != token::Comma {
@@ -2654,24 +2662,28 @@ impl<'a> Parser<'a> {
         let seq_span = lo.to(self.prev_token.span);
         let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
         if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
-            err.multipart_suggestion(
-                format!(
-                    "try adding parentheses to match on a tuple{}",
-                    if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
-                ),
-                vec![
-                    (seq_span.shrink_to_lo(), "(".to_string()),
-                    (seq_span.shrink_to_hi(), ")".to_string()),
-                ],
-                Applicability::MachineApplicable,
-            );
-            if let CommaRecoveryMode::EitherTupleOrPipe = rt {
-                err.span_suggestion(
-                    seq_span,
-                    "...or a vertical bar to match on multiple alternatives",
-                    seq_snippet.replace(',', " |"),
+            if is_mac_invoc {
+                err.note(fluent::parse_macro_expands_to_match_arm);
+            } else {
+                err.multipart_suggestion(
+                    format!(
+                        "try adding parentheses to match on a tuple{}",
+                        if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
+                    ),
+                    vec![
+                        (seq_span.shrink_to_lo(), "(".to_string()),
+                        (seq_span.shrink_to_hi(), ")".to_string()),
+                    ],
                     Applicability::MachineApplicable,
                 );
+                if let CommaRecoveryMode::EitherTupleOrPipe = rt {
+                    err.span_suggestion(
+                        seq_span,
+                        "...or a vertical bar to match on multiple alternatives",
+                        seq_snippet.replace(',', " |"),
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
         }
         Err(err)
@@ -2772,7 +2784,7 @@ impl<'a> Parser<'a> {
     /// sequence of patterns until `)` is reached.
     fn skip_pat_list(&mut self) -> PResult<'a, ()> {
         while !self.check(&token::CloseDelim(Delimiter::Parenthesis)) {
-            self.parse_pat_no_top_alt(None)?;
+            self.parse_pat_no_top_alt(None, None)?;
             if !self.eat(&token::Comma) {
                 return Ok(());
             }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index dc3b131e7f2..c0459789805 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2338,7 +2338,7 @@ impl<'a> Parser<'a> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
-            let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName))?;
+            let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?;
             let ty = if this.eat(&token::Colon) {
                 this.parse_ty()?
             } else {
@@ -2781,7 +2781,7 @@ impl<'a> Parser<'a> {
                 return None;
             }
             let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
-            match self.parse_pat_no_top_alt(None) {
+            match self.parse_pat_no_top_alt(None, None) {
                 Ok(_pat) => {
                     if self.token.kind == token::FatArrow {
                         // Reached arm end.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e9cc858c8c5..24c65d061f9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,8 +1,8 @@
-use crate::errors;
-
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
+use crate::errors::{self, MacroExpandsToAdtField};
+use crate::fluent_generated as fluent;
 use ast::StaticItem;
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
@@ -1450,6 +1450,17 @@ impl<'a> Parser<'a> {
                 }
                 let ident = this.parse_field_ident("enum", vlo)?;
 
+                if this.token == token::Not {
+                    if let Err(mut err) = this.unexpected::<()>() {
+                        err.note(fluent::parse_macro_expands_to_enum_variant).emit();
+                    }
+
+                    this.bump();
+                    this.parse_delim_args()?;
+
+                    return Ok((None, TrailingToken::MaybeComma));
+                }
+
                 let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
                     // Parse a struct variant.
                     let (fields, recovered) =
@@ -1477,7 +1488,7 @@ impl<'a> Parser<'a> {
 
                 Ok((Some(vr), TrailingToken::MaybeComma))
             },
-        ).map_err(|mut err|{
+        ).map_err(|mut err| {
             err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
             err
         })
@@ -1687,7 +1698,8 @@ impl<'a> Parser<'a> {
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
             let vis = this.parse_visibility(FollowedByType::No)?;
-            Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None))
+            this.parse_single_struct_field(adt_ty, lo, vis, attrs)
+                .map(|field| (field, TrailingToken::None))
         })
     }
 
@@ -1821,8 +1833,8 @@ impl<'a> Parser<'a> {
                     "field names and their types are separated with `:`",
                     ":",
                     Applicability::MachineApplicable,
-                );
-                err.emit();
+                )
+                .emit();
             } else {
                 return Err(err);
             }
@@ -1839,6 +1851,23 @@ impl<'a> Parser<'a> {
         attrs: AttrVec,
     ) -> PResult<'a, FieldDef> {
         let name = self.parse_field_ident(adt_ty, lo)?;
+        // Parse the macro invocation and recover
+        if self.token.kind == token::Not {
+            if let Err(mut err) = self.unexpected::<FieldDef>() {
+                err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
+                self.bump();
+                self.parse_delim_args()?;
+                return Ok(FieldDef {
+                    span: DUMMY_SP,
+                    ident: None,
+                    vis,
+                    id: DUMMY_NODE_ID,
+                    ty: self.mk_ty(DUMMY_SP, TyKind::Err),
+                    attrs,
+                    is_placeholder: false,
+                });
+            }
+        }
         self.expect_field_ty_separator()?;
         let ty = self.parse_ty()?;
         if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index adb0d372a40..f5681532b3a 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -131,7 +131,7 @@ impl<'a> Parser<'a> {
             },
             NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
                 token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
-                    NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None),
+                    NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None),
                     NonterminalKind::PatWithOr { .. } => this.parse_pat_allow_top_alt(
                         None,
                         RecoverComma::No,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index fed16278db5..4aadb7d7ca5 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -2,10 +2,11 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken};
 use crate::errors::{
     self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
     DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
-    ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
-    InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
-    RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
-    TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
+    ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
+    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
+    PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
+    TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
+    UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
     UnexpectedVertVertInPattern,
 };
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -80,7 +81,8 @@ enum EatOrResult {
 }
 
 /// The syntax location of a given pattern. Used for diagnostics.
-pub(super) enum PatternLocation {
+#[derive(Clone, Copy)]
+pub enum PatternLocation {
     LetBinding,
     FunctionParameter,
 }
@@ -91,8 +93,12 @@ impl<'a> Parser<'a> {
     /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
     /// at the top level. Used when parsing the parameters of lambda expressions,
     /// functions, function pointers, and `pat` macro fragments.
-    pub fn parse_pat_no_top_alt(&mut self, expected: Option<Expected>) -> PResult<'a, P<Pat>> {
-        self.parse_pat_with_range_pat(true, expected)
+    pub fn parse_pat_no_top_alt(
+        &mut self,
+        expected: Option<Expected>,
+        syntax_loc: Option<PatternLocation>,
+    ) -> PResult<'a, P<Pat>> {
+        self.parse_pat_with_range_pat(true, expected, syntax_loc)
     }
 
     /// Parses a pattern.
@@ -110,7 +116,7 @@ impl<'a> Parser<'a> {
         ra: RecoverColon,
         rt: CommaRecoveryMode,
     ) -> PResult<'a, P<Pat>> {
-        self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt).map(|(pat, _)| pat)
+        self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat)
     }
 
     /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
@@ -121,6 +127,7 @@ impl<'a> Parser<'a> {
         rc: RecoverComma,
         ra: RecoverColon,
         rt: CommaRecoveryMode,
+        syntax_loc: Option<PatternLocation>,
     ) -> PResult<'a, (P<Pat>, bool)> {
         // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated
         // suggestions (which bothers rustfix).
@@ -133,9 +140,13 @@ impl<'a> Parser<'a> {
         };
 
         // Parse the first pattern (`p_0`).
-        let mut first_pat = self.parse_pat_no_top_alt(expected)?;
+        let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?;
         if rc == RecoverComma::Yes {
-            self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
+            self.maybe_recover_unexpected_comma(
+                first_pat.span,
+                matches!(first_pat.kind, PatKind::MacCall(_)),
+                rt,
+            )?;
         }
 
         // If the next token is not a `|`,
@@ -172,12 +183,12 @@ impl<'a> Parser<'a> {
                     break;
                 }
             }
-            let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| {
+            let pat = self.parse_pat_no_top_alt(expected, syntax_loc).map_err(|mut err| {
                 err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
             if rc == RecoverComma::Yes {
-                self.maybe_recover_unexpected_comma(pat.span, rt)?;
+                self.maybe_recover_unexpected_comma(pat.span, false, rt)?;
             }
             pats.push(pat);
         }
@@ -208,6 +219,7 @@ impl<'a> Parser<'a> {
             rc,
             RecoverColon::No,
             CommaRecoveryMode::LikelyTuple,
+            Some(syntax_loc),
         )?;
         let colon = self.eat(&token::Colon);
 
@@ -319,6 +331,7 @@ impl<'a> Parser<'a> {
         &mut self,
         allow_range_pat: bool,
         expected: Option<Expected>,
+        syntax_loc: Option<PatternLocation>,
     ) -> PResult<'a, P<Pat>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
         maybe_whole!(self, NtPat, |x| x);
@@ -358,11 +371,11 @@ impl<'a> Parser<'a> {
             // Parse _
             PatKind::Wild
         } else if self.eat_keyword(kw::Mut) {
-            self.parse_pat_ident_mut()?
+            self.parse_pat_ident_mut(syntax_loc)?
         } else if self.eat_keyword(kw::Ref) {
             // Parse ref ident @ pat / ref mut ident @ pat
             let mutbl = self.parse_mutability();
-            self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))?
+            self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)?
         } else if self.eat_keyword(kw::Box) {
             self.parse_pat_box()?
         } else if self.check_inline_const(0) {
@@ -384,7 +397,7 @@ impl<'a> Parser<'a> {
             // Parse `ident @ pat`
             // This can give false positives and parse nullary enums,
             // they are dealt with later in resolve.
-            self.parse_pat_ident(BindingAnnotation::NONE)?
+            self.parse_pat_ident(BindingAnnotation::NONE, syntax_loc)?
         } else if self.is_start_of_pat_with_path() {
             // Parse pattern starting with a path
             let (qself, path) = if self.eat_lt() {
@@ -485,7 +498,7 @@ impl<'a> Parser<'a> {
 
         // At this point we attempt to parse `@ $pat_rhs` and emit an error.
         self.bump(); // `@`
-        let mut rhs = self.parse_pat_no_top_alt(None)?;
+        let mut rhs = self.parse_pat_no_top_alt(None, None)?;
         let whole_span = lhs.span.to(rhs.span);
 
         if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind {
@@ -541,7 +554,7 @@ impl<'a> Parser<'a> {
         }
 
         let mutbl = self.parse_mutability();
-        let subpat = self.parse_pat_with_range_pat(false, expected)?;
+        let subpat = self.parse_pat_with_range_pat(false, expected, None)?;
         Ok(PatKind::Ref(subpat, mutbl))
     }
 
@@ -566,12 +579,12 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a mutable binding with the `mut` token already eaten.
-    fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
+    fn parse_pat_ident_mut(&mut self, syntax_loc: Option<PatternLocation>) -> PResult<'a, PatKind> {
         let mut_span = self.prev_token.span;
 
         if self.eat_keyword(kw::Ref) {
             self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
-            return self.parse_pat_ident(BindingAnnotation::REF_MUT);
+            return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc);
         }
 
         self.recover_additional_muts();
@@ -584,7 +597,7 @@ impl<'a> Parser<'a> {
         }
 
         // Parse the pattern we hope to be an identifier.
-        let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier))?;
+        let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?;
 
         // If we don't have `mut $ident (@ pat)?`, error.
         if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
@@ -810,10 +823,25 @@ impl<'a> Parser<'a> {
     /// Parses `ident` or `ident @ pat`.
     /// Used by the copy foo and ref foo patterns to give a good
     /// error message when parsing mistakes like `ref foo(a, b)`.
-    fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> {
+    fn parse_pat_ident(
+        &mut self,
+        binding_annotation: BindingAnnotation,
+        syntax_loc: Option<PatternLocation>,
+    ) -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
+
+        if !matches!(syntax_loc, Some(PatternLocation::FunctionParameter))
+            && self.check_noexpect(&token::Lt)
+            && self.look_ahead(1, |t| t.can_begin_type())
+        {
+            return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax {
+                span: self.token.span,
+                suggest_turbofish: self.token.span.shrink_to_lo(),
+            }));
+        }
+
         let sub = if self.eat(&token::At) {
-            Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?)
+            Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?)
         } else {
             None
         };
@@ -902,14 +930,14 @@ impl<'a> Parser<'a> {
             // We cannot use `parse_pat_ident()` since it will complain `box`
             // is not an identifier.
             let sub = if self.eat(&token::At) {
-                Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?)
+                Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?)
             } else {
                 None
             };
 
             Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub))
         } else {
-            let pat = self.parse_pat_with_range_pat(false, None)?;
+            let pat = self.parse_pat_with_range_pat(false, None, None)?;
             self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
             Ok(PatKind::Box(pat))
         }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 4cf0f1305a7..53005ede843 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -11,6 +11,7 @@
 #![allow(rustc::potential_query_instability, unused_parens)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_middle;
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index da5e92a075a..e403386e60c 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -18,6 +18,7 @@
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
 #![allow(rustc::potential_query_instability)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index d57aa820fcb..a270817f310 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -10,6 +10,7 @@
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs
index 259f4238654..4811bb2c354 100644
--- a/compiler/rustc_span/src/edit_distance.rs
+++ b/compiler/rustc_span/src/edit_distance.rs
@@ -238,8 +238,9 @@ fn find_best_match_for_name_impl(
 }
 
 fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Symbol> {
+    let lookup_sorted_by_words = sort_by_words(lookup);
     iter_names.iter().fold(None, |result, candidate| {
-        if sort_by_words(candidate.as_str()) == sort_by_words(lookup) {
+        if sort_by_words(candidate.as_str()) == lookup_sorted_by_words {
             Some(*candidate)
         } else {
             result
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index fbd9bf05528..afee5c0fe2b 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -23,6 +23,7 @@
 #![feature(round_char_boundary)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d3739733c1d..9cff8a688ff 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1155,8 +1155,10 @@ symbols! {
         profiler_builtins,
         profiler_runtime,
         ptr,
+        ptr_cast,
         ptr_cast_mut,
         ptr_const_is_null,
+        ptr_from_mut,
         ptr_from_ref,
         ptr_guaranteed_cmp,
         ptr_is_null,
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 3307244a217..b52002b1239 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -19,6 +19,7 @@
 #![feature(step_trait)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 use std::path::{Path, PathBuf};
 
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index 88771f90756..a9d182abfb7 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -207,23 +207,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match self.canonicalize_mode {
-            CanonicalizeMode::Input => {
-                // Don't resolve infer vars in input, since it affects
-                // caching and may cause trait selection bugs which rely
-                // on regions to be equal.
-            }
-            CanonicalizeMode::Response { .. } => {
-                if let ty::ReVar(vid) = *r {
-                    r = self
-                        .infcx
-                        .inner
-                        .borrow_mut()
-                        .unwrap_region_constraints()
-                        .opportunistic_resolve_var(self.infcx.tcx, vid);
-                }
-            }
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReVar(vid) = *r {
+            let resolved_region = self
+                .infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(self.infcx.tcx, vid);
+            assert_eq!(
+                r, resolved_region,
+                "region var should have been resolved, {r} -> {resolved_region}"
+            );
         }
 
         let kind = match *r {
@@ -278,38 +273,22 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         ty::Region::new_late_bound(self.interner(), self.binder_index, br)
     }
 
-    fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         let kind = match *t.kind() {
-            ty::Infer(ty::TyVar(mut vid)) => {
-                // We need to canonicalize the *root* of our ty var.
-                // This is so that our canonical response correctly reflects
-                // any equated inference vars correctly!
-                let root_vid = self.infcx.root_var(vid);
-                if root_vid != vid {
-                    t = Ty::new_var(self.infcx.tcx, root_vid);
-                    vid = root_vid;
-                }
-
-                match self.infcx.probe_ty_var(vid) {
-                    Ok(t) => return self.fold_ty(t),
-                    Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
-                }
+            ty::Infer(ty::TyVar(vid)) => {
+                assert_eq!(self.infcx.root_var(vid), vid, "ty vid should have been resolved");
+                let Err(ui) = self.infcx.probe_ty_var(vid) else {
+                    bug!("ty var should have been resolved: {t}");
+                };
+                CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
             }
             ty::Infer(ty::IntVar(vid)) => {
-                let nt = self.infcx.opportunistic_resolve_int_var(vid);
-                if nt != t {
-                    return self.fold_ty(nt);
-                } else {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
-                }
+                assert_eq!(self.infcx.opportunistic_resolve_int_var(vid), t);
+                CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
             }
             ty::Infer(ty::FloatVar(vid)) => {
-                let nt = self.infcx.opportunistic_resolve_float_var(vid);
-                if nt != t {
-                    return self.fold_ty(nt);
-                } else {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
-                }
+                assert_eq!(self.infcx.opportunistic_resolve_float_var(vid), t);
+                CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
             }
             ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("fresh var during canonicalization: {t:?}")
@@ -372,22 +351,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         Ty::new_bound(self.infcx.tcx, self.binder_index, bt)
     }
 
-    fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let kind = match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => {
-                // We need to canonicalize the *root* of our const var.
-                // This is so that our canonical response correctly reflects
-                // any equated inference vars correctly!
-                let root_vid = self.infcx.root_const_var(vid);
-                if root_vid != vid {
-                    c = ty::Const::new_var(self.infcx.tcx, root_vid, c.ty());
-                    vid = root_vid;
-                }
-
-                match self.infcx.probe_const_var(vid) {
-                    Ok(c) => return self.fold_const(c),
-                    Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
-                }
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                assert_eq!(
+                    self.infcx.root_const_var(vid),
+                    vid,
+                    "const var should have been resolved"
+                );
+                let Err(ui) = self.infcx.probe_const_var(vid) else {
+                    bug!("const var should have been resolved");
+                };
+                // FIXME: we should fold this ty eventually
+                CanonicalVarKind::Const(ui, c.ty())
             }
             ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
                 bug!("fresh var during canonicalization: {c:?}")
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 7323b98b8ce..0a54b1c6433 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -16,11 +16,15 @@ use rustc_index::IndexVec;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
-    ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
+    ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
+};
+use rustc_middle::ty::{
+    self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt,
 };
-use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
 use rustc_span::DUMMY_SP;
 use std::iter;
 use std::ops::Deref;
@@ -32,6 +36,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         &self,
         goal: Goal<'tcx, T>,
     ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
+        let opaque_types = self.infcx.clone_opaque_types_for_query_response();
+        let (goal, opaque_types) =
+            (goal, opaque_types).fold_with(&mut EagerResolver { infcx: self.infcx });
+
         let mut orig_values = Default::default();
         let canonical_goal = Canonicalizer::canonicalize(
             self.infcx,
@@ -40,11 +48,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             QueryInput {
                 goal,
                 anchor: self.infcx.defining_use_anchor,
-                predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body(
-                    PredefinedOpaquesData {
-                        opaque_types: self.infcx.clone_opaque_types_for_query_response(),
-                    },
-                ),
+                predefined_opaques_in_body: self
+                    .tcx()
+                    .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
             },
         );
         (orig_values, canonical_goal)
@@ -70,34 +76,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         );
 
         let certainty = certainty.unify_with(goals_certainty);
+        if let Certainty::OVERFLOW = certainty {
+            // If we have overflow, it's probable that we're substituting a type
+            // into itself infinitely and any partial substitutions in the query
+            // response are probably not useful anyways, so just return an empty
+            // query response.
+            //
+            // This may prevent us from potentially useful inference, e.g.
+            // 2 candidates, one ambiguous and one overflow, which both
+            // have the same inference constraints.
+            //
+            // Changing this to retain some constraints in the future
+            // won't be a breaking change, so this is good enough for now.
+            return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
+        }
 
-        let response = match certainty {
-            Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => {
-                let external_constraints = self.compute_external_query_constraints()?;
-                Response { var_values: self.var_values, external_constraints, certainty }
-            }
-            Certainty::Maybe(MaybeCause::Overflow) => {
-                // If we have overflow, it's probable that we're substituting a type
-                // into itself infinitely and any partial substitutions in the query
-                // response are probably not useful anyways, so just return an empty
-                // query response.
-                //
-                // This may prevent us from potentially useful inference, e.g.
-                // 2 candidates, one ambiguous and one overflow, which both
-                // have the same inference constraints.
-                //
-                // Changing this to retain some constraints in the future
-                // won't be a breaking change, so this is good enough for now.
-                return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
-            }
-        };
+        let var_values = self.var_values;
+        let external_constraints = self.compute_external_query_constraints()?;
+
+        let (var_values, mut external_constraints) =
+            (var_values, external_constraints).fold_with(&mut EagerResolver { infcx: self.infcx });
+        // Remove any trivial region constraints once we've resolved regions
+        external_constraints
+            .region_constraints
+            .outlives
+            .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1));
 
         let canonical = Canonicalizer::canonicalize(
             self.infcx,
             CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
             &mut Default::default(),
-            response,
+            Response {
+                var_values,
+                certainty,
+                external_constraints: self.tcx().mk_external_constraints(external_constraints),
+            },
         );
+
         Ok(canonical)
     }
 
@@ -143,7 +158,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     /// further constrained by inference, that will be passed back in the var
     /// values.
     #[instrument(level = "debug", skip(self), ret)]
-    fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
+    fn compute_external_query_constraints(
+        &self,
+    ) -> Result<ExternalConstraintsData<'tcx>, NoSolution> {
         // We only check for leaks from universes which were entered inside
         // of the query.
         self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
@@ -173,9 +190,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
         });
 
-        Ok(self
-            .tcx()
-            .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
+        Ok(ExternalConstraintsData { region_constraints, opaque_types })
     }
 
     /// After calling a canonical query, we apply the constraints returned
@@ -333,3 +348,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         Ok(())
     }
 }
+
+/// Resolves ty, region, and const vars to their inferred values or their root vars.
+struct EagerResolver<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
+                Ok(t) => t.fold_with(self),
+                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
+            },
+            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
+            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
+            _ => {
+                if t.has_infer() {
+                    t.super_fold_with(self)
+                } else {
+                    t
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match *r {
+            ty::ReVar(vid) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(self.infcx.tcx, vid),
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match c.kind() {
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                // FIXME: we need to fold the ty too, I think.
+                match self.infcx.probe_const_var(vid) {
+                    Ok(c) => c.fold_with(self),
+                    Err(_) => {
+                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
+                    }
+                }
+            }
+            _ => {
+                if c.has_infer() {
+                    c.super_fold_with(self)
+                } else {
+                    c
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index bf09681c66d..cf9d2bda17e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -987,9 +987,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let target = self.infcx.shallow_resolve(target);
         debug!(?source, ?target, "confirm_builtin_unsize_candidate");
 
-        let mut nested = vec![];
-        let src;
-        match (source.kind(), target.kind()) {
+        Ok(match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
             (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b))
                 if dyn_a == dyn_b =>
@@ -1016,16 +1014,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
-                let InferOk { obligations, .. } = self
+                let InferOk { mut obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
                     .sup(DefineOpaqueTypes::No, target, source_trait)
                     .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
 
                 // Register one obligation for 'a: 'b.
                 let outlives = ty::OutlivesPredicate(r_a, r_b);
-                nested.push(Obligation::with_depth(
+                obligations.push(Obligation::with_depth(
                     tcx,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
@@ -1033,7 +1030,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.predicate.rebind(outlives),
                 ));
 
-                src = BuiltinImplSource::Misc;
+                ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
             }
 
             // `T` -> `Trait`
@@ -1059,11 +1056,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 //  words, if the object type is `Foo + Send`, this would create an obligation for
                 //  the `Send` check.)
                 //  - Projection predicates
-                nested.extend(
-                    data.iter().map(|predicate| {
-                        predicate_to_obligation(predicate.with_self_ty(tcx, source))
-                    }),
-                );
+                let mut nested: Vec<_> = data
+                    .iter()
+                    .map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source)))
+                    .collect();
 
                 // We can only make objects from sized types.
                 let tr = ty::TraitRef::from_lang_item(
@@ -1081,7 +1077,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
                 ));
 
-                src = BuiltinImplSource::Misc;
+                ImplSource::Builtin(BuiltinImplSource::Misc, nested)
             }
 
             // `[T; n]` -> `[T]`
@@ -1091,9 +1087,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .at(&obligation.cause, obligation.param_env)
                     .eq(DefineOpaqueTypes::No, b, a)
                     .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
 
-                src = BuiltinImplSource::Misc;
+                ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
             }
 
             // `Struct<T>` -> `Struct<U>`
@@ -1106,6 +1101,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let tail_field = def.non_enum_variant().tail();
                 let tail_field_ty = tcx.type_of(tail_field.did);
 
+                let mut nested = vec![];
+
                 // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
                 // normalizing in the process, since `type_of` returns something directly from
                 // astconv (which means it's un-normalized).
@@ -1151,7 +1148,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 );
                 nested.push(tail_unsize_obligation);
 
-                src = BuiltinImplSource::Misc;
+                ImplSource::Builtin(BuiltinImplSource::Misc, nested)
             }
 
             // `(.., T)` -> `(.., U)`
@@ -1166,27 +1163,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // last element is equal to the target.
                 let new_tuple =
                     Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last)));
-                let InferOk { obligations, .. } = self
+                let InferOk { mut obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
                     .eq(DefineOpaqueTypes::No, target, new_tuple)
                     .map_err(|_| Unimplemented)?;
-                nested.extend(obligations);
 
                 // Add a nested `T: Unsize<U>` predicate.
                 let last_unsize_obligation = obligation.with(
                     tcx,
                     ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
                 );
-                nested.push(last_unsize_obligation);
+                obligations.push(last_unsize_obligation);
 
-                src = BuiltinImplSource::TupleUnsizing;
+                ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, obligations)
             }
 
             _ => bug!("source: {source}, target: {target}"),
-        };
-
-        Ok(ImplSource::Builtin(src, nested))
+        })
     }
 
     fn confirm_const_destruct_candidate(
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index c2655d68b79..b0f8ea7a05d 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(unwrap_infallible)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[macro_use]
 extern crate bitflags;
@@ -215,6 +216,11 @@ bitflags! {
         /// Does this have `ConstKind::Placeholder`?
         const HAS_CT_PLACEHOLDER          = 1 << 8;
 
+        /// Does this have placeholders?
+        const HAS_PLACEHOLDER           = TypeFlags::HAS_TY_PLACEHOLDER.bits
+                                          | TypeFlags::HAS_RE_PLACEHOLDER.bits
+                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits;
+
         /// `true` if there are "names" of regions and so forth
         /// that are local to a particular fn/inferctxt
         const HAS_FREE_LOCAL_REGIONS      = 1 << 9;
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 967ad3a0e69..80681a7a7cf 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -88,6 +88,7 @@
 #![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
 #![warn(multiple_supertrait_upcastable)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 //
 // Library features:
 // tidy-alphabetical-start
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 5944a0de1a4..036edbebbf3 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -14,6 +14,7 @@
 //!
 //! ```rust
 //! #![feature(core_intrinsics, custom_mir)]
+#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")]
 //!
 //! use core::intrinsics::mir::*;
 //!
@@ -63,6 +64,7 @@
 //!
 //! ```rust
 //! #![feature(core_intrinsics, custom_mir)]
+#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")]
 //!
 //! use core::intrinsics::mir::*;
 //!
@@ -315,6 +317,7 @@ define!(
     /// # Examples
     ///
     /// ```rust
+    #[cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")]
     /// #![feature(custom_mir, core_intrinsics)]
     ///
     /// use core::intrinsics::mir::*;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 37216d6a721..ded799160bf 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -96,6 +96,7 @@
 #![allow(explicit_outlives_requirements)]
 #![allow(incomplete_features)]
 #![warn(multiple_supertrait_upcastable)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 //
 // Library features:
 // tidy-alphabetical-start
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index acc9ca29d41..5f094ac4e7e 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -710,6 +710,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 #[inline(always)]
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[rustc_diagnostic_item = "ptr_from_mut"]
 pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
     r
 }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index e7f27439540..e3a3f69afd9 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -54,6 +54,7 @@ impl<T: ?Sized> *mut T {
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
     #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
+    #[rustc_diagnostic_item = "ptr_cast"]
     #[inline(always)]
     pub const fn cast<U>(self) -> *mut U {
         self as _
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index b193d79b0e1..76b35919658 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -14,6 +14,7 @@
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
 #![feature(c_unwind)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[cfg(target_os = "android")]
 mod android;
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index ce78ab82ef9..2e5459321a2 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -26,6 +26,7 @@
 #![feature(c_unwind)]
 // `real_imp` is unused with Miri, so silence warnings.
 #![cfg_attr(miri, allow(dead_code))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 use alloc::boxed::Box;
 use core::any::Any;
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 2c0d113dbc5..be89afa32b3 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -33,6 +33,7 @@
 #![feature(min_specialization)]
 #![feature(strict_provenance)]
 #![recursion_limit = "256"]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
diff --git a/library/profiler_builtins/src/lib.rs b/library/profiler_builtins/src/lib.rs
index 0c83bcee06f..a81d0a63547 100644
--- a/library/profiler_builtins/src/lib.rs
+++ b/library/profiler_builtins/src/lib.rs
@@ -7,4 +7,5 @@
     issue = "none"
 )]
 #![allow(unused_features)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![feature(staged_api)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 238c74229cc..2f9cd7bc0ca 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -220,6 +220,7 @@
 #![warn(missing_debug_implementations)]
 #![allow(explicit_outlives_requirements)]
 #![allow(unused_lifetimes)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![deny(rustc::existing_doc_keyword)]
 #![deny(fuzzy_provenance_casts)]
 // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 7d49bbdcbe0..4d17a1b0002 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -89,6 +89,12 @@ enum FdMeta {
     NoneObtained,
 }
 
+#[derive(PartialEq)]
+enum FdHandle {
+    Input,
+    Output,
+}
+
 impl FdMeta {
     fn maybe_fifo(&self) -> bool {
         match self {
@@ -114,12 +120,14 @@ impl FdMeta {
         }
     }
 
-    fn copy_file_range_candidate(&self) -> bool {
+    fn copy_file_range_candidate(&self, f: FdHandle) -> bool {
         match self {
             // copy_file_range will fail on empty procfs files. `read` can determine whether EOF has been reached
             // without extra cost and skip the write, thus there is no benefit in attempting copy_file_range
-            FdMeta::Metadata(meta) if meta.is_file() && meta.len() > 0 => true,
-            FdMeta::NoneObtained => true,
+            FdMeta::Metadata(meta) if f == FdHandle::Input && meta.is_file() && meta.len() > 0 => {
+                true
+            }
+            FdMeta::Metadata(meta) if f == FdHandle::Output && meta.is_file() => true,
             _ => false,
         }
     }
@@ -197,7 +205,9 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
             written += flush()?;
             let max_write = reader.min_limit();
 
-            if input_meta.copy_file_range_candidate() && output_meta.copy_file_range_candidate() {
+            if input_meta.copy_file_range_candidate(FdHandle::Input)
+                && output_meta.copy_file_range_candidate(FdHandle::Output)
+            {
                 let result = copy_regular_files(readfd, writefd, max_write);
                 result.update_take(reader);
 
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 0bd447552cf..64d10dd5712 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -21,6 +21,7 @@
 #![feature(process_exitcode_internals)]
 #![feature(panic_can_unwind)]
 #![feature(test)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 // Public reexports
 pub use self::bench::{black_box, Bencher};
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index b655bae9673..0b4daeafe46 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -5,6 +5,7 @@
 #![feature(c_unwind)]
 #![feature(cfg_target_abi)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 
 cfg_if::cfg_if! {
     if #[cfg(target_env = "msvc")] {
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 2c51ed5408e..bdefc41c9c7 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -307,6 +307,12 @@ impl Step for CodegenBackend {
     }
 
     fn run(self, builder: &Builder<'_>) {
+        // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved
+        if builder.build.config.vendor && &self.backend == "gcc" {
+            println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
+            return;
+        }
+
         let compiler = builder.compiler(builder.top_stage, builder.config.build);
         let target = self.target;
         let backend = self.backend;
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 983442270d2..2c63ec80c3e 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -23,7 +23,7 @@ use crate::builder::crate_description;
 use crate::builder::Cargo;
 use crate::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
 use crate::cache::{Interned, INTERNER};
-use crate::config::{LlvmLibunwind, RustcLto, TargetSelection};
+use crate::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
 use crate::dist;
 use crate::llvm;
 use crate::tool::SourceType;
@@ -888,16 +888,37 @@ impl Step for Rustc {
             compiler.host,
             target,
         );
+        let stamp = librustc_stamp(builder, compiler, target);
         run_cargo(
             builder,
             cargo,
             vec![],
-            &librustc_stamp(builder, compiler, target),
+            &stamp,
             vec![],
             false,
             true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
         );
 
+        // When building `librustc_driver.so` (like `libLLVM.so`) on linux, it can contain
+        // unexpected debuginfo from dependencies, for example from the C++ standard library used in
+        // our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with
+        // debuginfo (via the debuginfo level of the executables using it): strip this debuginfo
+        // away after the fact.
+        // FIXME: to make things simpler for now, limit this to the host and target where we know
+        // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not
+        // cross-compiling. Expand this to other appropriate targets in the future.
+        if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None
+            && builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None
+            && target == "x86_64-unknown-linux-gnu"
+            && target == builder.config.build
+        {
+            let target_root_dir = stamp.parent().unwrap();
+            let rustc_driver = target_root_dir.join("librustc_driver.so");
+            if rustc_driver.exists() {
+                output(Command::new("strip").arg("--strip-debug").arg(rustc_driver));
+            }
+        }
+
         builder.ensure(RustcLink::from_rustc(
             self,
             builder.compiler(compiler.stage, builder.config.build),
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 45bea9608fc..bec0b11acd0 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -50,7 +50,7 @@ pub enum DryRun {
     UserSelected,
 }
 
-#[derive(Copy, Clone, Default)]
+#[derive(Copy, Clone, Default, PartialEq, Eq)]
 pub enum DebuginfoLevel {
     #[default]
     None,
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index 81b88d5de98..0613b999793 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -485,25 +485,56 @@ impl Step for Llvm {
 
         cfg.build();
 
-        // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
-        // libLLVM.dylib will be built. However, llvm-config will still look
-        // for a versioned path like libLLVM-14.dylib. Manually create a symbolic
-        // link to make llvm-config happy.
-        if builder.llvm_link_shared() && target.contains("apple-darwin") {
+        // Helper to find the name of LLVM's shared library on darwin and linux.
+        let find_llvm_lib_name = |extension| {
             let mut cmd = Command::new(&res.llvm_config);
             let version = output(cmd.arg("--version"));
             let major = version.split('.').next().unwrap();
-            let lib_name = match llvm_version_suffix {
-                Some(s) => format!("libLLVM-{major}{s}.dylib"),
-                None => format!("libLLVM-{major}.dylib"),
+            let lib_name = match &llvm_version_suffix {
+                Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"),
+                None => format!("libLLVM-{major}.{extension}"),
             };
+            lib_name
+        };
 
+        // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
+        // libLLVM.dylib will be built. However, llvm-config will still look
+        // for a versioned path like libLLVM-14.dylib. Manually create a symbolic
+        // link to make llvm-config happy.
+        if builder.llvm_link_shared() && target.contains("apple-darwin") {
+            let lib_name = find_llvm_lib_name("dylib");
             let lib_llvm = out_dir.join("build").join("lib").join(lib_name);
             if !lib_llvm.exists() {
                 t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
             }
         }
 
+        // When building LLVM as a shared library on linux, it can contain unexpected debuginfo:
+        // some can come from the C++ standard library. Unless we're explicitly requesting LLVM to
+        // be built with debuginfo, strip it away after the fact, to make dist artifacts smaller.
+        // FIXME: to make things simpler for now, limit this to the host and target where we know
+        // `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not
+        // cross-compiling. Expand this to other appropriate targets in the future.
+        if builder.llvm_link_shared()
+            && builder.config.llvm_optimize
+            && !builder.config.llvm_release_debuginfo
+            && target == "x86_64-unknown-linux-gnu"
+            && target == builder.config.build
+        {
+            // Find the name of the LLVM shared library that we just built.
+            let lib_name = find_llvm_lib_name("so");
+
+            // If the shared library exists in LLVM's `/build/lib/` or `/lib/` folders, strip its
+            // debuginfo. Note: `output` will propagate any errors here.
+            let strip_if_possible = |path: PathBuf| {
+                if path.exists() {
+                    output(Command::new("strip").arg("--strip-debug").arg(path));
+                }
+            };
+            strip_if_possible(out_dir.join("lib").join(&lib_name));
+            strip_if_possible(out_dir.join("build").join("lib").join(&lib_name));
+        }
+
         t!(stamp.write());
 
         res
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 013b93e0129..f69156b7c05 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -200,6 +200,7 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
 
 ```rust
 #![feature(rustdoc_internals)]
+#![allow(internal_features)]
 
 /// Some documentation about the keyword.
 #[doc(keyword = "keyword")]
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index ea9bace6dd4..8fa8f567d7e 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -17,6 +17,7 @@ via a declaration like
 
 ```rust
 #![feature(intrinsics)]
+#![allow(internal_features)]
 # fn main() {}
 
 extern "rust-intrinsic" {
diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md
index f4bc18bc7da..1f3d472c3aa 100644
--- a/src/doc/unstable-book/src/language-features/lang-items.md
+++ b/src/doc/unstable-book/src/language-features/lang-items.md
@@ -17,6 +17,7 @@ sugar for dynamic allocations via `malloc` and `free`:
 
 ```rust,ignore (libc-is-finicky)
 #![feature(lang_items, start, libc, core_intrinsics, rustc_private, rustc_attrs)]
+#![allow(internal_features)]
 #![no_std]
 use core::intrinsics;
 use core::panic::PanicInfo;
@@ -119,6 +120,7 @@ in the same format as C:
 ```rust,ignore (libc-is-finicky)
 #![feature(lang_items, core_intrinsics, rustc_private)]
 #![feature(start)]
+#![allow(internal_features)]
 #![no_std]
 use core::intrinsics;
 use core::panic::PanicInfo;
@@ -155,6 +157,7 @@ compiler's name mangling too:
 ```rust,ignore (libc-is-finicky)
 #![feature(lang_items, core_intrinsics, rustc_private)]
 #![feature(start)]
+#![allow(internal_features)]
 #![no_std]
 #![no_main]
 use core::intrinsics;
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 020651c52257052d28f6fd83fbecf5cfa1ed516
+Subproject d78bbf4bde3c6b95caca7512f537c6f9721426f
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 49bdc679604..fc1fabcc0ae 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -43,7 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
     ("clippy::forget_copy", "forgetting_copy_types"),
     ("clippy::forget_ref", "forgetting_references"),
-    ("clippy::fn_null_check", "incorrect_fn_null_checks"),
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
     ("clippy::into_iter_on_array", "array_into_iter"),
     ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
     ("clippy::invalid_ref", "invalid_value"),
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 5d7e1494fcf..a43a81bc63a 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -1011,6 +1011,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                         },
                         // note: unable to trigger `Subslice` kind in tests
                         ProjectionKind::Subslice => (),
+                        // Doesn't have surface syntax. Only occurs in patterns.
+                        ProjectionKind::OpaqueCast => (),
                         ProjectionKind::Deref => {
                             // Explicit derefs are typically handled later on, but
                             // some items do not need explicit deref, such as array accesses,
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 385e25ce6b8..e46f8bf6fab 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -140,6 +140,7 @@ fn base_config(test_dir: &str) -> compiletest::Config {
         [
             "--emit=metadata",
             "-Aunused",
+            "-Ainternal_features",
             "-Zui-testing",
             "-Dwarnings",
             &format!("-Ldependency={}", deps_path.display()),
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 8ec19b120d1..8257bf2947a 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -38,7 +38,7 @@
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
 #![allow(forgetting_references)]
-#![allow(incorrect_fn_null_checks)]
+#![allow(useless_ptr_null_checks)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
@@ -92,7 +92,7 @@
 #![warn(for_loops_over_fallibles)]
 #![warn(forgetting_copy_types)]
 #![warn(forgetting_references)]
-#![warn(incorrect_fn_null_checks)]
+#![warn(useless_ptr_null_checks)]
 #![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
 #![warn(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 51a5976eb61..6569dad18d4 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -38,7 +38,7 @@
 #![allow(for_loops_over_fallibles)]
 #![allow(forgetting_copy_types)]
 #![allow(forgetting_references)]
-#![allow(incorrect_fn_null_checks)]
+#![allow(useless_ptr_null_checks)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index e420ea1d2ad..57e991e5695 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -246,11 +246,11 @@ error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
-error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks`
+error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
   --> $DIR/rename.rs:95:9
    |
 LL | #![warn(clippy::fn_null_check)]
-   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks`
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
   --> $DIR/rename.rs:96:9
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 45582ddcbaf..07a54cb26d3 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -868,6 +868,8 @@ impl<'test> TestCx<'test> {
             .args(&["--target", &self.config.target])
             .arg("-L")
             .arg(&aux_dir)
+            .arg("-A")
+            .arg("internal_features")
             .args(&self.props.compile_flags)
             .envs(self.props.rustc_env.clone());
         self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
@@ -936,7 +938,9 @@ impl<'test> TestCx<'test> {
             .arg("-L")
             .arg(&self.config.build_base)
             .arg("-L")
-            .arg(aux_dir);
+            .arg(aux_dir)
+            .arg("-A")
+            .arg("internal_features");
         self.set_revision_flags(&mut rustc);
         self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
         rustc.args(&self.props.compile_flags);
@@ -1867,6 +1871,8 @@ impl<'test> TestCx<'test> {
             .arg("--deny")
             .arg("warnings")
             .arg(&self.testpaths.file)
+            .arg("-A")
+            .arg("internal_features")
             .args(&self.props.compile_flags);
 
         if self.config.mode == RustdocJson {
@@ -1933,7 +1939,8 @@ impl<'test> TestCx<'test> {
                 let mut test_client =
                     Command::new(self.config.remote_test_client.as_ref().unwrap());
                 test_client
-                    .args(&["run", &support_libs.len().to_string(), &prog])
+                    .args(&["run", &support_libs.len().to_string()])
+                    .arg(&prog)
                     .args(support_libs)
                     .args(args);
 
@@ -2459,6 +2466,9 @@ impl<'test> TestCx<'test> {
             rustc.args(&["-A", "unused"]);
         }
 
+        // Allow tests to use internal features.
+        rustc.args(&["-A", "internal_features"]);
+
         if self.props.force_host {
             self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags);
             if !is_rustdoc {
@@ -2516,7 +2526,7 @@ impl<'test> TestCx<'test> {
         // If this is emscripten, then run tests under nodejs
         if self.config.target.contains("emscripten") {
             if let Some(ref p) = self.config.nodejs {
-                args.push(p.clone());
+                args.push(p.into());
             } else {
                 self.fatal("emscripten target requested and no NodeJS binary found (--nodejs)");
             }
@@ -2524,7 +2534,7 @@ impl<'test> TestCx<'test> {
         // shim
         } else if self.config.target.contains("wasm32") {
             if let Some(ref p) = self.config.nodejs {
-                args.push(p.clone());
+                args.push(p.into());
             } else {
                 self.fatal("wasm32 target requested and no NodeJS binary found (--nodejs)");
             }
@@ -2536,13 +2546,12 @@ impl<'test> TestCx<'test> {
                 .unwrap() // chop off `ui`
                 .parent()
                 .unwrap(); // chop off `tests`
-            args.push(src.join("src/etc/wasm32-shim.js").display().to_string());
+            args.push(src.join("src/etc/wasm32-shim.js").into_os_string());
         }
 
         let exe_file = self.make_exe_name();
 
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        args.push(exe_file.to_str().unwrap().to_owned());
+        args.push(exe_file.into_os_string());
 
         // Add the arguments in the run_flags directive
         args.extend(self.split_maybe_args(&self.props.run_flags));
@@ -2551,12 +2560,16 @@ impl<'test> TestCx<'test> {
         ProcArgs { prog, args }
     }
 
-    fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<String> {
+    fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<OsString> {
         match *argstr {
             Some(ref s) => s
                 .split(' ')
                 .filter_map(|s| {
-                    if s.chars().all(|c| c.is_whitespace()) { None } else { Some(s.to_owned()) }
+                    if s.chars().all(|c| c.is_whitespace()) {
+                        None
+                    } else {
+                        Some(OsString::from(s))
+                    }
                 })
                 .collect(),
             None => Vec::new(),
@@ -4363,8 +4376,8 @@ impl<'test> TestCx<'test> {
 }
 
 struct ProcArgs {
-    prog: String,
-    args: Vec<String>,
+    prog: OsString,
+    args: Vec<OsString>,
 }
 
 pub struct ProcRes {
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 8d9901807ec..6bd4be91e51 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -273,6 +273,8 @@ pub fn report_error<'tcx, 'mir>(
     } else {
         #[rustfmt::skip]
         let title = match e.kind() {
+            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(e)) if matches!(e.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
+                bug!("This validation error should be impossible in Miri: {:?}", e.kind),
             UndefinedBehavior(_) =>
                 "Undefined Behavior",
             ResourceExhaustion(_) =>
@@ -377,7 +379,7 @@ pub fn report_error<'tcx, 'mir>(
     if let Some((alloc_id, access)) = extra {
         eprintln!(
             "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
-            range = access.uninit,
+            range = access.bad,
         );
         eprintln!("{:?}", ecx.dump_alloc(alloc_id));
     }
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index fa17923446f..5c3a194214b 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -53,6 +53,7 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
     // Add some flags we always want.
     program.args.push("-Dwarnings".into());
     program.args.push("-Dunused".into());
+    program.args.push("-Ainternal_features".into());
     if let Ok(extra_flags) = env::var("MIRIFLAGS") {
         for flag in extra_flags.split_whitespace() {
             program.args.push(flag.into());
diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr
index 677a0fc5570..e95e3b18128 100644
--- a/src/tools/miri/tests/fail/validity/uninit_float.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes
+error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number
   --> $DIR/uninit_float.rs:LL:CC
    |
 LL |     let _val: [f32; 1] = unsafe { std::mem::uninitialized() };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number
    |
    = 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/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr
index a9ac2a6dc67..2156886cd71 100644
--- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes
+error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer
   --> $DIR/uninit_integer.rs:LL:CC
    |
 LL |     let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer
    |
    = 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/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs
index 67f3985926e..7a802f7a88e 100644
--- a/src/tools/rustfmt/src/parse/macros/mod.rs
+++ b/src/tools/rustfmt/src/parse/macros/mod.rs
@@ -56,7 +56,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
     );
     parse_macro_arg!(
         Pat,
-        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None),
+        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None, None),
         |x: ptr::P<ast::Pat>| Some(x)
     );
     // `parse_item` returns `Option<ptr::P<ast::Item>>`.
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 7ad8f5c5c05..d900c04c124 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -338,6 +338,7 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
         let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) {
             Some("active") => Status::Unstable,
             Some("incomplete") => Status::Unstable,
+            Some("internal") => Status::Unstable,
             Some("removed") => Status::Removed,
             Some("accepted") => Status::Stable,
             _ => continue,
diff --git a/tests/incremental/issue-61530.rs b/tests/incremental/issue-61530.rs
index edb3d60ba3f..1dcb41ddeda 100644
--- a/tests/incremental/issue-61530.rs
+++ b/tests/incremental/issue-61530.rs
@@ -6,13 +6,13 @@
 struct I32x2(i32, i32);
 
 extern "platform-intrinsic" {
-    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
+    fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 }
 
 fn main() {
     unsafe {
         const IDX: [u32; 2] = [0, 0];
-        let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), IDX);
-        let _: I32x2 = simd_shuffle2(I32x2(1, 2), I32x2(3, 4), IDX);
+        let _: I32x2 = simd_shuffle(I32x2(1, 2), I32x2(3, 4), IDX);
+        let _: I32x2 = simd_shuffle(I32x2(1, 2), I32x2(3, 4), IDX);
     }
 }
diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff
index f3f4d895ae2..8f2baf4a3b6 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.panic-abort.diff
@@ -5,13 +5,10 @@
       let mut _0: ();
       let _1: ();
 +     let mut _2: fn() {main};
-+     let mut _5: ();
 +     scope 1 (inlined f::<fn() {main}>) {
 +         debug g => _2;
 +         let mut _3: &fn() {main};
 +         let _4: ();
-+         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
-+         }
 +     }
   
       bb0: {
@@ -22,9 +19,7 @@
 +         StorageLive(_4);
 +         StorageLive(_3);
 +         _3 = &_2;
-+         StorageLive(_5);
-+         _5 = const ();
-+         _4 = move (*_3)() -> [return: bb2, unwind unreachable];
++         _4 = <fn() {main} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind unreachable];
       }
   
       bb1: {
@@ -36,7 +31,6 @@
 +     }
 + 
 +     bb2: {
-+         StorageDead(_5);
 +         StorageDead(_3);
 +         drop(_2) -> [return: bb1, unwind unreachable];
       }
diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
index 3ce8d9acf36..ad801fd280a 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
@@ -5,13 +5,10 @@
       let mut _0: ();
       let _1: ();
 +     let mut _2: fn() {main};
-+     let mut _5: ();
 +     scope 1 (inlined f::<fn() {main}>) {
 +         debug g => _2;
 +         let mut _3: &fn() {main};
 +         let _4: ();
-+         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
-+         }
 +     }
   
       bb0: {
@@ -22,9 +19,7 @@
 +         StorageLive(_4);
 +         StorageLive(_3);
 +         _3 = &_2;
-+         StorageLive(_5);
-+         _5 = const ();
-+         _4 = move (*_3)() -> [return: bb4, unwind: bb2];
++         _4 = <fn() {main} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind: bb3];
       }
   
       bb1: {
@@ -35,18 +30,17 @@
           return;
 +     }
 + 
-+     bb2 (cleanup): {
-+         drop(_2) -> [return: bb3, unwind terminate];
++     bb2: {
++         StorageDead(_3);
++         drop(_2) -> [return: bb1, unwind continue];
 +     }
 + 
 +     bb3 (cleanup): {
-+         resume;
++         drop(_2) -> [return: bb4, unwind terminate];
 +     }
 + 
-+     bb4: {
-+         StorageDead(_5);
-+         StorageDead(_3);
-+         drop(_2) -> [return: bb1, unwind continue];
++     bb4 (cleanup): {
++         resume;
       }
   }
   
diff --git a/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff b/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff
index eb007635416..fd1f698c60d 100644
--- a/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/cycle.main.Inline.panic-abort.diff
@@ -5,21 +5,10 @@
       let mut _0: ();
       let _1: ();
 +     let mut _2: fn() {g};
-+     let mut _5: ();
 +     scope 1 (inlined f::<fn() {g}>) {
 +         debug g => _2;
 +         let mut _3: &fn() {g};
 +         let _4: ();
-+         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) {
-+             scope 3 (inlined g) {
-+                 scope 4 (inlined f::<fn() {main}>) {
-+                     debug g => main;
-+                     let _6: ();
-+                     scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
-+                     }
-+                 }
-+             }
-+         }
 +     }
   
       bb0: {
@@ -30,10 +19,7 @@
 +         StorageLive(_4);
 +         StorageLive(_3);
 +         _3 = &_2;
-+         StorageLive(_5);
-+         _5 = const ();
-+         StorageLive(_6);
-+         _6 = main() -> [return: bb2, unwind unreachable];
++         _4 = <fn() {g} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind unreachable];
       }
   
       bb1: {
@@ -45,8 +31,6 @@
 +     }
 + 
 +     bb2: {
-+         StorageDead(_6);
-+         StorageDead(_5);
 +         StorageDead(_3);
 +         drop(_2) -> [return: bb1, unwind unreachable];
       }
diff --git a/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff
index 198a2322618..99dc64115a9 100644
--- a/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff
@@ -5,21 +5,10 @@
       let mut _0: ();
       let _1: ();
 +     let mut _2: fn() {g};
-+     let mut _5: ();
 +     scope 1 (inlined f::<fn() {g}>) {
 +         debug g => _2;
 +         let mut _3: &fn() {g};
 +         let _4: ();
-+         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) {
-+             scope 3 (inlined g) {
-+                 scope 4 (inlined f::<fn() {main}>) {
-+                     debug g => main;
-+                     let _6: ();
-+                     scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) {
-+                     }
-+                 }
-+             }
-+         }
 +     }
   
       bb0: {
@@ -30,10 +19,7 @@
 +         StorageLive(_4);
 +         StorageLive(_3);
 +         _3 = &_2;
-+         StorageLive(_5);
-+         _5 = const ();
-+         StorageLive(_6);
-+         _6 = main() -> [return: bb4, unwind: bb2];
++         _4 = <fn() {g} as Fn<()>>::call(move _3, const ()) -> [return: bb2, unwind: bb3];
       }
   
       bb1: {
@@ -44,19 +30,17 @@
           return;
 +     }
 + 
-+     bb2 (cleanup): {
-+         drop(_2) -> [return: bb3, unwind terminate];
++     bb2: {
++         StorageDead(_3);
++         drop(_2) -> [return: bb1, unwind continue];
 +     }
 + 
 +     bb3 (cleanup): {
-+         resume;
++         drop(_2) -> [return: bb4, unwind terminate];
 +     }
 + 
-+     bb4: {
-+         StorageDead(_6);
-+         StorageDead(_5);
-+         StorageDead(_3);
-+         drop(_2) -> [return: bb1, unwind continue];
++     bb4 (cleanup): {
++         resume;
       }
   }
   
diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff
new file mode 100644
index 00000000000..757617e5940
--- /dev/null
+++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-abort.diff
@@ -0,0 +1,29 @@
+- // MIR for `call` before Inline
++ // MIR for `call` after Inline
+  
+  fn call(_1: Box<dyn FnMut<I, Output = ()>>, _2: I) -> () {
+      debug mock => _1;
+      debug input => _2;
+      let mut _0: ();
+      let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
+      let mut _4: I;
+  
+      bb0: {
+          StorageLive(_3);
+          _3 = &mut _1;
+          StorageLive(_4);
+          _4 = move _2;
+          _0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_4);
+          StorageDead(_3);
+          drop(_1) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..ef85e075eeb
--- /dev/null
+++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.call.Inline.panic-unwind.diff
@@ -0,0 +1,37 @@
+- // MIR for `call` before Inline
++ // MIR for `call` after Inline
+  
+  fn call(_1: Box<dyn FnMut<I, Output = ()>>, _2: I) -> () {
+      debug mock => _1;
+      debug input => _2;
+      let mut _0: ();
+      let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
+      let mut _4: I;
+  
+      bb0: {
+          StorageLive(_3);
+          _3 = &mut _1;
+          StorageLive(_4);
+          _4 = move _2;
+          _0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind: bb3];
+      }
+  
+      bb1: {
+          StorageDead(_4);
+          StorageDead(_3);
+          drop(_1) -> [return: bb2, unwind: bb4];
+      }
+  
+      bb2: {
+          return;
+      }
+  
+      bb3 (cleanup): {
+          drop(_1) -> [return: bb4, unwind terminate];
+      }
+  
+      bb4 (cleanup): {
+          resume;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs
new file mode 100644
index 00000000000..971223c72ca
--- /dev/null
+++ b/tests/mir-opt/inline/dont_ice_on_generic_rust_call.rs
@@ -0,0 +1,11 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// compile-flags: -Zmir-enable-passes=+Inline --crate-type=lib
+
+#![feature(fn_traits, tuple_trait, unboxed_closures)]
+
+use std::marker::Tuple;
+
+// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff
+pub fn call<I: Tuple>(mut mock: Box<dyn FnMut<I, Output = ()>>, input: I) {
+    mock.call_mut(input)
+}
diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-abort.diff
new file mode 100644
index 00000000000..4fa04b05e89
--- /dev/null
+++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-abort.diff
@@ -0,0 +1,32 @@
+- // MIR for `call` before Inline
++ // MIR for `call` after Inline
+  
+  fn call(_1: Box<dyn Fn(i32)>) -> () {
+      debug x => _1;
+      let mut _0: ();
+      let _2: ();
+      let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
+      let mut _4: (i32,);
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = &_1;
+          StorageLive(_4);
+          _4 = (const 1_i32,);
+          _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_4);
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          drop(_1) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..5df730a9930
--- /dev/null
+++ b/tests/mir-opt/inline/inline_box_fn.call.Inline.panic-unwind.diff
@@ -0,0 +1,40 @@
+- // MIR for `call` before Inline
++ // MIR for `call` after Inline
+  
+  fn call(_1: Box<dyn Fn(i32)>) -> () {
+      debug x => _1;
+      let mut _0: ();
+      let _2: ();
+      let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
+      let mut _4: (i32,);
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = &_1;
+          StorageLive(_4);
+          _4 = (const 1_i32,);
+          _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind: bb3];
+      }
+  
+      bb1: {
+          StorageDead(_4);
+          StorageDead(_3);
+          StorageDead(_2);
+          _0 = const ();
+          drop(_1) -> [return: bb2, unwind: bb4];
+      }
+  
+      bb2: {
+          return;
+      }
+  
+      bb3 (cleanup): {
+          drop(_1) -> [return: bb4, unwind terminate];
+      }
+  
+      bb4 (cleanup): {
+          resume;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/inline_box_fn.rs b/tests/mir-opt/inline/inline_box_fn.rs
new file mode 100644
index 00000000000..348f0e77f92
--- /dev/null
+++ b/tests/mir-opt/inline/inline_box_fn.rs
@@ -0,0 +1,8 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// unit-test: Inline
+// compile-flags: --crate-type=lib
+
+// EMIT_MIR inline_box_fn.call.Inline.diff
+fn call(x: Box<dyn Fn(i32)>) {
+    x(1);
+}
diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff
index d83c8d585ea..8a6eec3352a 100644
--- a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-abort.diff
@@ -5,20 +5,9 @@
       let mut _0: ();
       let _1: ();
 +     let mut _2: fn() {f};
-+     let mut _4: ();
 +     scope 1 (inlined call::<fn() {f}>) {
 +         debug f => _2;
 +         let _3: ();
-+         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) {
-+             scope 3 (inlined f) {
-+                 scope 4 (inlined call::<fn() {f}>) {
-+                     debug f => f;
-+                     let _5: ();
-+                     scope 5 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) {
-+                     }
-+                 }
-+             }
-+         }
 +     }
   
       bb0: {
@@ -27,15 +16,10 @@
 +         StorageLive(_2);
 +         _2 = f;
 +         StorageLive(_3);
-+         StorageLive(_4);
-+         _4 = const ();
-+         StorageLive(_5);
-+         _5 = f() -> [return: bb1, unwind unreachable];
++         _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, const ()) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
-+         StorageDead(_5);
-+         StorageDead(_4);
 +         StorageDead(_3);
 +         StorageDead(_2);
           StorageDead(_1);
diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff
index a08662959dd..a24649c1ebd 100644
--- a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff
@@ -5,20 +5,9 @@
       let mut _0: ();
       let _1: ();
 +     let mut _2: fn() {f};
-+     let mut _4: ();
 +     scope 1 (inlined call::<fn() {f}>) {
 +         debug f => _2;
 +         let _3: ();
-+         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) {
-+             scope 3 (inlined f) {
-+                 scope 4 (inlined call::<fn() {f}>) {
-+                     debug f => f;
-+                     let _5: ();
-+                     scope 5 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) {
-+                     }
-+                 }
-+             }
-+         }
 +     }
   
       bb0: {
@@ -27,15 +16,10 @@
 +         StorageLive(_2);
 +         _2 = f;
 +         StorageLive(_3);
-+         StorageLive(_4);
-+         _4 = const ();
-+         StorageLive(_5);
-+         _5 = f() -> [return: bb1, unwind continue];
++         _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, const ()) -> [return: bb1, unwind continue];
       }
   
       bb1: {
-+         StorageDead(_5);
-+         StorageDead(_4);
 +         StorageDead(_3);
 +         StorageDead(_2);
           StorageDead(_1);
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff
index 0dcd5fae88d..7d5553b2f37 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff
@@ -5,7 +5,6 @@
       let mut _0: ();
       let _1: (!, !);
 +     let mut _2: fn() -> ! {sleep};
-+     let mut _7: ();
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
 +         debug f => _2;
 +         let mut _3: &fn() -> ! {sleep};
@@ -18,10 +17,6 @@
 +                 debug b => _6;
 +             }
 +         }
-+         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) {
-+             scope 5 (inlined sleep) {
-+             }
-+         }
 +     }
   
       bb0: {
@@ -33,13 +28,24 @@
 +         StorageLive(_6);
 +         StorageLive(_3);
 +         _3 = &_2;
-+         StorageLive(_7);
-+         _7 = const ();
-+         goto -> bb1;
++         _4 = <fn() -> ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind unreachable];
 +     }
 + 
 +     bb1: {
-+         goto -> bb1;
++         StorageDead(_3);
++         StorageLive(_5);
++         _5 = &_2;
++         _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind unreachable];
++     }
++ 
++     bb2: {
++         StorageDead(_5);
++         _1 = (move _4, move _6);
++         drop(_2) -> [return: bb3, unwind unreachable];
++     }
++ 
++     bb3: {
++         unreachable;
       }
   }
   
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
index dfc12db12a8..073ddeff7ca 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
@@ -5,7 +5,6 @@
       let mut _0: ();
       let _1: (!, !);
 +     let mut _2: fn() -> ! {sleep};
-+     let mut _8: ();
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
 +         debug f => _2;
 +         let mut _3: &fn() -> ! {sleep};
@@ -19,10 +18,6 @@
 +                 debug b => _6;
 +             }
 +         }
-+         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) {
-+             scope 5 (inlined sleep) {
-+             }
-+         }
 +     }
   
       bb0: {
@@ -34,13 +29,40 @@
 +         StorageLive(_4);
 +         StorageLive(_3);
 +         _3 = &_2;
-+         StorageLive(_8);
-+         _8 = const ();
-+         goto -> bb1;
++         _4 = <fn() -> ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind: bb5];
 +     }
 + 
 +     bb1: {
-+         goto -> bb1;
++         StorageDead(_3);
++         StorageLive(_5);
++         _5 = &_2;
++         _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind: bb4];
++     }
++ 
++     bb2: {
++         StorageDead(_5);
++         StorageLive(_7);
++         _7 = move _4;
++         _1 = (move _7, move _6);
++         StorageDead(_7);
++         StorageDead(_4);
++         drop(_2) -> [return: bb3, unwind continue];
++     }
++ 
++     bb3: {
++         unreachable;
++     }
++ 
++     bb4 (cleanup): {
++         drop(_4) -> [return: bb5, unwind terminate];
++     }
++ 
++     bb5 (cleanup): {
++         drop(_2) -> [return: bb6, unwind terminate];
++     }
++ 
++     bb6 (cleanup): {
++         resume;
       }
   }
   
diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff
index b86eb5f35c9..bee01a5f97b 100644
--- a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff
@@ -8,8 +8,6 @@
       let mut _3: &fn() {foo};
       let _4: fn() {foo};
       let mut _5: ();
-+     scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) {
-+     }
   
       bb0: {
           StorageLive(_2);
@@ -22,26 +20,20 @@
           _3 = &_4;
           StorageLive(_5);
           _5 = ();
--         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind unreachable];
-+         _2 = move (*_3)() -> [return: bb3, unwind unreachable];
+          _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
-+         return;
-+     }
-+ 
-+     bb3: {
           StorageDead(_5);
           StorageDead(_3);
           StorageDead(_4);
           StorageDead(_2);
           _0 = const ();
--         drop(_1) -> [return: bb3, unwind unreachable];
--     }
-- 
--     bb3: {
--         return;
-+         drop(_1) -> [return: bb2, unwind unreachable];
+          drop(_1) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          return;
       }
   }
   
diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff
index c67babba23e..b750330df92 100644
--- a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff
@@ -8,55 +8,40 @@
       let mut _3: &fn() {foo};
       let _4: fn() {foo};
       let mut _5: ();
-+     scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) {
-+     }
   
       bb0: {
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
--         _4 = hide_foo() -> [return: bb1, unwind: bb4];
-+         _4 = hide_foo() -> [return: bb1, unwind: bb3];
+          _4 = hide_foo() -> [return: bb1, unwind: bb4];
       }
   
       bb1: {
           _3 = &_4;
           StorageLive(_5);
           _5 = ();
--         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4];
-+         _2 = move (*_3)() -> [return: bb5, unwind: bb3];
+          _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4];
       }
   
       bb2: {
--         StorageDead(_5);
--         StorageDead(_3);
--         StorageDead(_4);
--         StorageDead(_2);
--         _0 = const ();
--         drop(_1) -> [return: bb3, unwind: bb5];
-+         return;
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_4);
+          StorageDead(_2);
+          _0 = const ();
+          drop(_1) -> [return: bb3, unwind: bb5];
       }
   
--     bb3: {
--         return;
-+     bb3 (cleanup): {
-+         drop(_1) -> [return: bb4, unwind terminate];
+      bb3: {
+          return;
       }
   
       bb4 (cleanup): {
--         drop(_1) -> [return: bb5, unwind terminate];
-+         resume;
+          drop(_1) -> [return: bb5, unwind terminate];
       }
   
--     bb5 (cleanup): {
--         resume;
-+     bb5: {
-+         StorageDead(_5);
-+         StorageDead(_3);
-+         StorageDead(_4);
-+         StorageDead(_2);
-+         _0 = const ();
-+         drop(_1) -> [return: bb2, unwind: bb4];
+      bb5 (cleanup): {
+          resume;
       }
   }
   
diff --git a/tests/run-make/tools.mk b/tests/run-make/tools.mk
index ea06b620c4c..6121a91e920 100644
--- a/tests/run-make/tools.mk
+++ b/tests/run-make/tools.mk
@@ -8,7 +8,7 @@ TARGET_RPATH_ENV = \
 RUSTC_ORIGINAL := $(RUSTC)
 BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)'
 BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)'
-RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS)
+RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) -Ainternal_features
 RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR)
 ifdef RUSTC_LINKER
 RUSTC := $(RUSTC) -Clinker='$(RUSTC_LINKER)'
diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml
index 4bdf31ecb19..404e5740305 100644
--- a/tests/rustdoc-gui/pocket-menu.goml
+++ b/tests/rustdoc-gui/pocket-menu.goml
@@ -29,52 +29,39 @@ click: "#help-button"
 assert-css: ("#help-button .popover", {"display": "none"})
 assert-css: ("#settings-menu .popover", {"display": "none"})
 
-// We check the borders color now:
-
-// Ayu theme
-set-local-storage: {
-    "rustdoc-theme": "ayu",
-    "rustdoc-use-system-theme": "false",
-}
-reload:
-
-click: "#help-button"
-assert-css: (
-    "#help-button .popover",
-    {"display": "block", "border-color": "rgb(92, 103, 115)"},
-)
-compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
-compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
-
-// Dark theme
-set-local-storage: {
-    "rustdoc-theme": "dark",
-    "rustdoc-use-system-theme": "false",
-}
-reload:
+define-function: (
+    "check-popover-colors",
+    (theme, border_color),
+    block {
+        set-local-storage: {
+            "rustdoc-theme": |theme|,
+            "rustdoc-use-system-theme": "false",
+        }
+        reload:
 
-click: "#help-button"
-assert-css: (
-    "#help-button .popover",
-    {"display": "block", "border-color": "rgb(224, 224, 224)"},
+        click: "#help-button"
+        assert-css: (
+            "#help-button .popover",
+            {"display": "block", "border-color": |border_color|},
+        )
+        compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+        compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+    }
 )
-compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
-compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
-
-// Light theme
-set-local-storage: {
-    "rustdoc-theme": "light",
-    "rustdoc-use-system-theme": "false",
-}
-reload:
 
-click: "#help-button"
-assert-css: (
-    "#help-button .popover",
-    {"display": "block", "border-color": "rgb(224, 224, 224)"},
-)
-compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
-compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+// We check the borders color now:
+call-function: ("check-popover-colors", {
+    "theme": "ayu",
+    "border_color": "#5c6773",
+})
+call-function: ("check-popover-colors", {
+    "theme": "dark",
+    "border_color": "#e0e0e0",
+})
+call-function: ("check-popover-colors", {
+    "theme": "light",
+    "border_color": "#e0e0e0",
+})
 
 // Opening the mobile sidebar should close the settings popover.
 set-window-size: (650, 600)
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 33210c9fdc9..88546ed2549 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -141,7 +141,7 @@ call-function: ("check-colors", {
     "theme": "ayu",
     "color": "#c5c5c5",
     "color_hover": "#ffb44c",
-    "background": "rgb(20, 25, 31)",
+    "background": "#14191f",
     "background_hover": "#14191f",
     "background_toggle": "rgba(0, 0, 0, 0)",
     "background_toggle_hover": "rgba(70, 70, 70, 0.33)",
diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs
index 5934593a899..0c914470e28 100644
--- a/tests/rustdoc-gui/src/staged_api/lib.rs
+++ b/tests/rustdoc-gui/src/staged_api/lib.rs
@@ -1,4 +1,5 @@
 #![feature(staged_api)]
+#![allow(internal_features)]
 #![stable(feature = "some_feature", since = "1.3.5")]
 
 #[stable(feature = "some_feature", since = "1.3.5")]
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index ecf3a7cc147..49484ee0869 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -3,6 +3,7 @@
 #![doc(html_playground_url="https://play.rust-lang.org/")]
 
 #![crate_name = "test_docs"]
+#![allow(internal_features)]
 #![feature(rustdoc_internals)]
 #![feature(doc_cfg)]
 #![feature(associated_type_defaults)]
diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs
index 2e9b13d0cac..8e39f471824 100644
--- a/tests/rustdoc-json/type/inherent_associated_type_bound.rs
+++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs
@@ -5,14 +5,15 @@
 // @set Carrier = '$.index[*][?(@.name=="Carrier")].id'
 pub struct Carrier<'a>(&'a ());
 
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.generic_params[*].name' \""'b"\"
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\"
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.trait' null
-// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'
-
-pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
+// @count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1
+// @is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"'
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\"
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\"
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"'
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null
+// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"'
+pub fn user(_: for<'b> fn(Carrier<'b>::Focus<i32>)) {}
 
 impl<'a> Carrier<'a> {
     pub type Focus<T> = &'a mut T;
diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs
index 942e323efca..d12e5f4a784 100644
--- a/tests/rustdoc-json/type/inherent_associated_type_projections.rs
+++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs
@@ -5,11 +5,13 @@
 // @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id'
 pub struct Parametrized<T>(T);
 
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.id' $Parametrized
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\"
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.name' '"Proj"'
-// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.trait' null
-pub type Test = Parametrized<i32>::Proj;
+// @count "$.index[*][?(@.name=='test')].inner.function.decl.inputs[*]" 1
+// @is "$.index[*][?(@.name=='test')].inner.function.decl.inputs[0][0]" '"_"'
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\"
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.name' '"Proj"'
+// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.trait' null
+pub fn test(_: Parametrized<i32>::Proj) {}
 
 /// param_bool
 impl Parametrized<bool> {
diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc/inherent-projections.rs
index 9bda0acaf83..25f51282617 100644
--- a/tests/rustdoc/inherent-projections.rs
+++ b/tests/rustdoc/inherent-projections.rs
@@ -13,8 +13,8 @@ impl Owner {
 }
 
 // Make sure we handle bound vars correctly.
-// @has 'inherent_projections/type.User.html' '//pre[@class="rust item-decl"]' "for<'a> fn(_: Carrier<'a>::Focus)"
-pub type User = for<'a> fn(Carrier<'a>::Focus);
+// @has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(_: Carrier<'a>::Focus))"
+pub fn user(_: for<'a> fn(Carrier<'a>::Focus)) {}
 
 pub struct Carrier<'a>(&'a ());
 
@@ -27,11 +27,11 @@ impl<'a> Carrier<'a> {
 // FIXME(inherent_associated_types): Below we link to `Proj` but we should link to `Proj-1`.
 // The current test checks for the buggy behavior for demonstration purposes.
 
-// @has 'inherent_projections/type.Test.html'
-// @has - '//pre[@class="rust item-decl"]' "Parametrized<i32>"
+// @has 'inherent_projections/fn.test.html'
+// @has - '//pre[@class="rust item-decl"]' "test(_: Parametrized<i32>::Proj)"
 // @has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj'
 // @!has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj-1'
-pub type Test = Parametrized<i32>::Proj;
+pub fn test(_: Parametrized<i32>::Proj) {}
 
 pub struct Parametrized<T>(T);
 
diff --git a/tests/rustdoc/issue-18199.rs b/tests/rustdoc/issue-18199.rs
index bc0c4a56502..9cc58b162f3 100644
--- a/tests/rustdoc/issue-18199.rs
+++ b/tests/rustdoc/issue-18199.rs
@@ -3,6 +3,7 @@
 #![doc(test(attr(feature(staged_api))))]
 
 /// ```
+/// #![allow(internal_features)]
 /// #![unstable(feature="test", issue="18199")]
 /// fn main() {}
 /// ```
diff --git a/tests/ui/associated-inherent-types/issue-111879-0.rs b/tests/ui/associated-inherent-types/issue-111879-0.rs
index e37f7d34ab5..d01354465df 100644
--- a/tests/ui/associated-inherent-types/issue-111879-0.rs
+++ b/tests/ui/associated-inherent-types/issue-111879-0.rs
@@ -5,10 +5,8 @@
 
 pub struct Carrier<'a>(&'a ());
 
-pub type User = for<'b> fn(Carrier<'b>::Focus<i32>);
-
 impl<'a> Carrier<'a> {
-    pub type Focus<T> = &'a mut User; //~ ERROR overflow evaluating associated type
+    pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>); //~ ERROR overflow evaluating associated type
 }
 
 fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-111879-0.stderr b/tests/ui/associated-inherent-types/issue-111879-0.stderr
index 7bdbad44017..f6367c88aea 100644
--- a/tests/ui/associated-inherent-types/issue-111879-0.stderr
+++ b/tests/ui/associated-inherent-types/issue-111879-0.stderr
@@ -1,8 +1,8 @@
 error: overflow evaluating associated type `Carrier<'b>::Focus<i32>`
-  --> $DIR/issue-111879-0.rs:11:25
+  --> $DIR/issue-111879-0.rs:9:25
    |
-LL |     pub type Focus<T> = &'a mut User;
-   |                         ^^^^^^^^^^^^
+LL |     pub type Focus<T> = &'a mut for<'b> fn(Carrier<'b>::Focus<i32>);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/associated-inherent-types/late-bound-regions.rs b/tests/ui/associated-inherent-types/late-bound-regions.rs
index 488a2cda649..1dbeb00d495 100644
--- a/tests/ui/associated-inherent-types/late-bound-regions.rs
+++ b/tests/ui/associated-inherent-types/late-bound-regions.rs
@@ -3,8 +3,6 @@
 
 // Test if we correctly normalize `S<'a>::P` with respect to late-bound regions.
 
-type Function = for<'a> fn(&'a i32) -> S<'a>::P;
-
 struct S<'a>(&'a ());
 
 trait Inter {
@@ -16,7 +14,7 @@ impl<'a> S<'a> {
 }
 
 fn ret_ref_local<'e>() -> &'e i32 {
-    let f: Function = |x| x;
+    let f: for<'a> fn(&'a i32) -> S<'a>::P = |x| x;
 
     let local = 0;
     f(&local) //~ ERROR cannot return value referencing local variable `local`
diff --git a/tests/ui/associated-inherent-types/late-bound-regions.stderr b/tests/ui/associated-inherent-types/late-bound-regions.stderr
index 4706fcca91d..0dd17b05cd0 100644
--- a/tests/ui/associated-inherent-types/late-bound-regions.stderr
+++ b/tests/ui/associated-inherent-types/late-bound-regions.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing local variable `local`
-  --> $DIR/late-bound-regions.rs:22:5
+  --> $DIR/late-bound-regions.rs:20:5
    |
 LL |     f(&local)
    |     ^^------^
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr
deleted file mode 100644
index 4396435a6dd..00000000000
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
-  --> $DIR/not-found-self-type-differs.rs:17:34
-   |
-LL | struct Family<T>(T);
-   | ---------------- associated item `Proj` not found for this struct
-...
-LL | type Alias = Family<Option<()>>::Proj;
-   |                                  ^^^^ associated item not found in `Family<Option<()>>`
-   |
-   = note: the associated type was found for
-           - `Family<()>`
-           - `Family<Result<T, ()>>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr
deleted file mode 100644
index d527db02217..00000000000
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
-  --> $DIR/not-found-self-type-differs.rs:21:40
-   |
-LL | struct Family<T>(T);
-   | ---------------- associated item `Proj` not found for this struct
-...
-LL |     let _: Family<std::path::PathBuf>::Proj = ();
-   |                                        ^^^^ associated item not found in `Family<PathBuf>`
-   |
-   = note: the associated type was found for
-           - `Family<()>`
-           - `Family<Result<T, ()>>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs.rs
index 93f58dcb6e6..76c5d4e7f69 100644
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs.rs
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs.rs
@@ -1,5 +1,3 @@
-// revisions: local alias
-
 #![feature(inherent_associated_types)]
 #![allow(incomplete_features)]
 
@@ -13,10 +11,7 @@ impl<T> Family<Result<T, ()>> {
     type Proj = Self;
 }
 
-#[cfg(alias)]
-type Alias = Family<Option<()>>::Proj; //[alias]~ ERROR associated type `Proj` not found for `Family<Option<()>>`
-
 fn main() {
-    #[cfg(local)]
-    let _: Family<std::path::PathBuf>::Proj = (); //[local]~ ERROR associated type `Proj` not found for `Family<PathBuf>`
+    let _: Family<Option<()>>::Proj; //~ ERROR associated type `Proj` not found for `Family<Option<()>>`
+    let _: Family<std::path::PathBuf>::Proj = (); //~ ERROR associated type `Proj` not found for `Family<PathBuf>`
 }
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr
new file mode 100644
index 00000000000..1871407c64f
--- /dev/null
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr
@@ -0,0 +1,29 @@
+error[E0220]: associated type `Proj` not found for `Family<Option<()>>` in the current scope
+  --> $DIR/not-found-self-type-differs.rs:15:32
+   |
+LL | struct Family<T>(T);
+   | ---------------- associated item `Proj` not found for this struct
+...
+LL |     let _: Family<Option<()>>::Proj;
+   |                                ^^^^ associated item not found in `Family<Option<()>>`
+   |
+   = note: the associated type was found for
+           - `Family<()>`
+           - `Family<Result<T, ()>>`
+
+error[E0220]: associated type `Proj` not found for `Family<PathBuf>` in the current scope
+  --> $DIR/not-found-self-type-differs.rs:16:40
+   |
+LL | struct Family<T>(T);
+   | ---------------- associated item `Proj` not found for this struct
+...
+LL |     let _: Family<std::path::PathBuf>::Proj = ();
+   |                                        ^^^^ associated item not found in `Family<PathBuf>`
+   |
+   = note: the associated type was found for
+           - `Family<()>`
+           - `Family<Result<T, ()>>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-inherent-types/substitute-params-bad.rs b/tests/ui/associated-inherent-types/substitute-params-bad.rs
index 00eb1a14da4..a5d73c7b49f 100644
--- a/tests/ui/associated-inherent-types/substitute-params-bad.rs
+++ b/tests/ui/associated-inherent-types/substitute-params-bad.rs
@@ -17,7 +17,7 @@ impl<T, S> Subj<(T, S)> {
 }
 
 fn main() {
-    type A = S<()>::P;
+    let _: S<()>::P;
 
     let _: Subj<(i32, i32)>::Un = 0i32; //~ ERROR mismatched types
 }
diff --git a/tests/ui/associated-inherent-types/substitute-params.rs b/tests/ui/associated-inherent-types/substitute-params.rs
index e94d6833159..631340b2b4d 100644
--- a/tests/ui/associated-inherent-types/substitute-params.rs
+++ b/tests/ui/associated-inherent-types/substitute-params.rs
@@ -15,8 +15,7 @@ impl<T> S<(T,)> {
 
 fn main() {
     // Regression test for issue #104240.
-    type A = S<()>::P;
-    let _: A = ();
+    let _: S<()>::P = ();
 
     // Regression test for issue #107468.
     let _: S<(i32,)>::Un = 0i32;
diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs
index b32b4288ac9..5c59f217be6 100644
--- a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs
+++ b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs
@@ -1,4 +1,5 @@
-// check-pass
+// FIXME(inherent_associated_types): This should be `check-pass`
+// known-bug: #108491
 // compile-flags: --crate-type=lib
 
 #![feature(inherent_associated_types)]
@@ -17,7 +18,6 @@
 
 pub type Alias<T: Bound> = (Source<T>::Assoc,);
 
-
 pub struct Source<T>(T);
 pub trait Bound {}
 
diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr
new file mode 100644
index 00000000000..5e18543fc90
--- /dev/null
+++ b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr
@@ -0,0 +1,55 @@
+error[E0391]: cycle detected when expanding type alias `Alias`
+  --> $DIR/type-alias-bounds-are-enforced.rs:19:1
+   |
+LL | pub type Alias<T: Bound> = (Source<T>::Assoc,);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing the variances of `Source`...
+  --> $DIR/type-alias-bounds-are-enforced.rs:21:1
+   |
+LL | pub struct Source<T>(T);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing the variances for items in this crate...
+   = note: ...which again requires expanding type alias `Alias`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/type-alias-bounds-are-enforced.rs:5:1
+   |
+LL | / #![feature(inherent_associated_types)]
+LL | | #![allow(incomplete_features)]
+LL | |
+LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*).
+...  |
+LL | |     pub type Assoc = ();
+LL | | }
+   | |_^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error[E0391]: cycle detected when expanding type alias `Alias`
+  --> $DIR/type-alias-bounds-are-enforced.rs:19:1
+   |
+LL | pub type Alias<T: Bound> = (Source<T>::Assoc,);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing the variances of `Source`...
+  --> $DIR/type-alias-bounds-are-enforced.rs:21:1
+   |
+LL | pub struct Source<T>(T);
+   | ^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires computing the variances for items in this crate...
+   = note: ...which again requires expanding type alias `Alias`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/type-alias-bounds-are-enforced.rs:5:1
+   |
+LL | / #![feature(inherent_associated_types)]
+LL | | #![allow(incomplete_features)]
+LL | |
+LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*).
+...  |
+LL | |     pub type Assoc = ();
+LL | | }
+   | |_^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr
index 22c3dfa64fe..294bc77aa31 100644
--- a/tests/ui/const-ptr/forbidden_slices.stderr
+++ b/tests/ui/const-ptr/forbidden_slices.stderr
@@ -41,7 +41,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:26:1
    |
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -52,8 +52,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:28:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
@@ -75,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:33:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -143,7 +144,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:53:1
    |
 LL | pub static R4: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -154,8 +155,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:58:1
    |
 LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
index bf98d03946d..f099bc7ef7c 100644
--- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
+++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:26:49
    |
 LL |     const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:29:43
    |
 LL |     const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 };
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:32:45
    |
 LL |     const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -29,7 +29,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:35:45
    |
 LL |     const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -38,7 +38,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:38:45
    |
 LL |     const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -53,7 +53,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:45:43
    |
 LL |     const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 };
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -62,7 +62,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:48:45
    |
 LL |     const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -71,7 +71,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:51:45
    |
 LL |     const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -80,7 +80,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:54:45
    |
 LL |     const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -95,7 +95,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:61:45
    |
 LL |     const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -104,7 +104,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:64:45
    |
 LL |     const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -113,7 +113,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:67:47
    |
 LL |     const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey };
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -122,7 +122,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:70:47
    |
 LL |     const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character };
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -131,7 +131,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:73:39
    |
 LL |     const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -140,7 +140,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:76:41
    |
 LL |     const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -149,7 +149,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:79:41
    |
 LL |     const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -158,7 +158,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:82:41
    |
 LL |     const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -167,7 +167,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:85:43
    |
 LL |     const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 };
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -176,7 +176,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:88:39
    |
 LL |     const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -185,7 +185,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:91:41
    |
 LL |     const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -194,7 +194,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:94:41
    |
 LL |     const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -203,7 +203,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:97:41
    |
 LL |     const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -212,7 +212,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:100:43
    |
 LL |     const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 };
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -221,7 +221,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:103:41
    |
 LL |     const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -230,7 +230,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:106:41
    |
 LL |     const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -239,7 +239,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:109:43
    |
 LL |     const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey };
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -248,7 +248,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:112:43
    |
 LL |     const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character };
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index 8a5424b3a6c..e087a0ebec7 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -266,7 +266,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:144:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected a string
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -277,7 +277,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:146:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized memory, but expected a string
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -288,8 +288,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:148:1
    |
 LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer, but expected a string
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 01 00 00 00                         │ ╾──╼....
            }
@@ -516,7 +517,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:215:1
    |
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -527,8 +528,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:218:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -550,7 +552,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:225:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -561,7 +563,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:232:1
    |
 LL | pub static R4: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -572,8 +574,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:237:1
    |
 LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID╼ 04 00 00 00                         │ ╾──╼....
            }
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index 08b98b37bd8..4c655161f79 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -266,7 +266,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:144:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected a string
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -277,7 +277,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:146:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized memory, but expected a string
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -288,8 +288,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:148:1
    |
 LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer, but expected a string
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -516,7 +517,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:215:1
    |
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -527,8 +528,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:218:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -550,7 +552,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:225:1
    |
 LL | pub static S7: &[u16] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -561,7 +563,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:232:1
    |
 LL | pub static R4: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -572,8 +574,9 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:237:1
    |
 LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
    |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
index eaa2d6b2794..8175fe6016a 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ref_to_int_match.rs:24:27
    |
 LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
-   |                           ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                           ^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
index eaa2d6b2794..8175fe6016a 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ref_to_int_match.rs:24:27
    |
 LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
-   |                           ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                           ^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr
index 5ef0d0146f2..c0ad6caecf2 100644
--- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr
@@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -22,7 +22,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:33:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -42,7 +42,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -51,7 +51,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -66,7 +66,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:64:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr
index c28a1b722ae..6db43d379d1 100644
--- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr
@@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -22,7 +22,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:33:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -42,7 +42,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -51,7 +51,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -66,7 +66,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:64:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/const-eval/ub-int-array.32bit.stderr b/tests/ui/consts/const-eval/ub-int-array.32bit.stderr
index edcde13b0e0..b3df41304ac 100644
--- a/tests/ui/consts/const-eval/ub-int-array.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-int-array.32bit.stderr
@@ -1,20 +1,35 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-int-array.rs:15:9
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-int-array.rs:19:1
    |
-LL |         MaybeUninit { uninit: () }.init,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+LL | const UNINIT_INT_0: [u32; 3] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected an integer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 12, align: 4) {
+               __ __ __ __ 01 00 00 00 02 00 00 00             │ ░░░░........
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-int-array.rs:30:13
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-int-array.rs:24:1
+   |
+LL | const UNINIT_INT_1: [u32; 3] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer
    |
-LL |             MaybeUninit { uninit: () }.init,
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 12, align: 4) {
+               00 00 00 00 01 __ 01 01 02 02 __ 02             │ .....░....░.
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-int-array.rs:56:13
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-int-array.rs:42:1
+   |
+LL | const UNINIT_INT_2: [u32; 3] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized memory, but expected an integer
    |
-LL |             MaybeUninit { uninit: () }.init,
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 12, align: 4) {
+               00 00 00 00 01 01 01 01 02 02 02 __             │ ...........░
+           }
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-eval/ub-int-array.64bit.stderr b/tests/ui/consts/const-eval/ub-int-array.64bit.stderr
index edcde13b0e0..b3df41304ac 100644
--- a/tests/ui/consts/const-eval/ub-int-array.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-int-array.64bit.stderr
@@ -1,20 +1,35 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-int-array.rs:15:9
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-int-array.rs:19:1
    |
-LL |         MaybeUninit { uninit: () }.init,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+LL | const UNINIT_INT_0: [u32; 3] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected an integer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 12, align: 4) {
+               __ __ __ __ 01 00 00 00 02 00 00 00             │ ░░░░........
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-int-array.rs:30:13
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-int-array.rs:24:1
+   |
+LL | const UNINIT_INT_1: [u32; 3] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer
    |
-LL |             MaybeUninit { uninit: () }.init,
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 12, align: 4) {
+               00 00 00 00 01 __ 01 01 02 02 __ 02             │ .....░....░.
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-int-array.rs:56:13
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-int-array.rs:42:1
+   |
+LL | const UNINIT_INT_2: [u32; 3] = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized memory, but expected an integer
    |
-LL |             MaybeUninit { uninit: () }.init,
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 12, align: 4) {
+               00 00 00 00 01 01 01 01 02 02 02 __             │ ...........░
+           }
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-eval/ub-int-array.rs b/tests/ui/consts/const-eval/ub-int-array.rs
index a68d3fb17bc..adcf376b9c7 100644
--- a/tests/ui/consts/const-eval/ub-int-array.rs
+++ b/tests/ui/consts/const-eval/ub-int-array.rs
@@ -10,54 +10,52 @@ union MaybeUninit<T: Copy> {
     init: T,
 }
 
+impl<T: Copy> MaybeUninit<T> {
+    const fn new(t: T) -> Self {
+        MaybeUninit { init: t }
+    }
+}
+
 const UNINIT_INT_0: [u32; 3] = unsafe {
-    [
-        MaybeUninit { uninit: () }.init,
-        //~^ ERROR evaluation of constant value failed
-        //~| uninitialized
-        1,
-        2,
-    ]
+    //~^ ERROR it is undefined behavior to use this value
+    //~| invalid value at [0]
+    mem::transmute([MaybeUninit { uninit: () }, MaybeUninit::new(1), MaybeUninit::new(2)])
 };
 const UNINIT_INT_1: [u32; 3] = unsafe {
-    mem::transmute(
-        [
-            0u8,
-            0u8,
-            0u8,
-            0u8,
-            1u8,
-            MaybeUninit { uninit: () }.init,
-            //~^ ERROR evaluation of constant value failed
-            //~| uninitialized
-            1u8,
-            1u8,
-            2u8,
-            2u8,
-            MaybeUninit { uninit: () }.init,
-            2u8,
-        ]
-    )
+    //~^ ERROR it is undefined behavior to use this value
+    //~| invalid value at [1]
+    mem::transmute([
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(1u8),
+        MaybeUninit { uninit: () },
+        MaybeUninit::new(1u8),
+        MaybeUninit::new(1u8),
+        MaybeUninit::new(2u8),
+        MaybeUninit::new(2u8),
+        MaybeUninit { uninit: () },
+        MaybeUninit::new(2u8),
+    ])
 };
 const UNINIT_INT_2: [u32; 3] = unsafe {
-    mem::transmute(
-        [
-            0u8,
-            0u8,
-            0u8,
-            0u8,
-            1u8,
-            1u8,
-            1u8,
-            1u8,
-            2u8,
-            2u8,
-            2u8,
-            MaybeUninit { uninit: () }.init,
-            //~^ ERROR evaluation of constant value failed
-            //~| uninitialized
-        ]
-    )
+    //~^ ERROR it is undefined behavior to use this value
+    //~| invalid value at [2]
+    mem::transmute([
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(0u8),
+        MaybeUninit::new(1u8),
+        MaybeUninit::new(1u8),
+        MaybeUninit::new(1u8),
+        MaybeUninit::new(1u8),
+        MaybeUninit::new(2u8),
+        MaybeUninit::new(2u8),
+        MaybeUninit::new(2u8),
+        MaybeUninit { uninit: () },
+    ])
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index d1644f8a4dc..0ee1e60877f 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -46,7 +46,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-ref-ptr.rs:33:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -55,7 +55,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-ref-ptr.rs:36:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -70,7 +70,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-ref-ptr.rs:39:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                                                                                      ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
index f38e7916b75..02bbbf50435 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-wide-ptr.rs:43:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -33,7 +33,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-wide-ptr.rs:46:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -53,7 +53,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:52:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected a string
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -64,7 +64,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:55:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized memory, but expected a string
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -103,7 +103,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-wide-ptr.rs:75:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
@@ -123,7 +123,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/ub-wide-ptr.rs:81:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs
index 5bff34bbe93..37b37e9659e 100644
--- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs
+++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs
@@ -1,7 +1,7 @@
 // revisions: no_flag with_flag
 // [no_flag] check-pass
 // [with_flag] compile-flags: -Zextra-const-ub-checks
-#![feature(never_type)]
+#![feature(never_type, pointer_byte_offsets)]
 
 use std::mem::transmute;
 use std::ptr::addr_of;
@@ -12,6 +12,9 @@ enum E { A, B }
 #[derive(Clone, Copy)]
 enum Never {}
 
+#[repr(usize)]
+enum PtrSizedEnum { V }
+
 // An enum with uninhabited variants but also at least 2 inhabited variants -- so the uninhabited
 // variants *do* have a discriminant.
 #[derive(Clone, Copy)]
@@ -31,12 +34,20 @@ const INVALID_BOOL: () = unsafe {
 const INVALID_PTR_IN_INT: () = unsafe {
     let _x: usize = transmute(&3u8);
     //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const INVALID_PTR_IN_ENUM: () = unsafe {
+    let _x: PtrSizedEnum = transmute(&3u8);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
 };
 
 const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
     let x: &[u8] = &[0; 32];
     let _x: (usize, usize) = transmute(x);
     //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
 };
 
 const UNALIGNED_PTR: () = unsafe {
@@ -50,6 +61,27 @@ const UNINHABITED_VARIANT: () = unsafe {
     // Not using transmute, we want to hit the ImmTy code path.
     let v = *addr_of!(data).cast::<UninhDiscriminant>();
     //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const PARTIAL_POINTER: () = unsafe {
+    #[repr(C, packed)]
+    struct Packed {
+        pad1: u8,
+        ptr: *const u8,
+        pad2: [u8; 7],
+    }
+    // `Align` ensures that the entire thing has pointer alignment again.
+    #[repr(C)]
+    struct Align {
+        p: Packed,
+        align: usize,
+    }
+    let mem = Packed { pad1: 0, ptr: &0u8 as *const u8, pad2: [0; 7] };
+    let mem = Align { p: mem, align: 0 };
+    let _val = *(&mem as *const Align as *const [*const u8; 2]);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
 };
 
 // Regression tests for an ICE (related to <https://github.com/rust-lang/rust/issues/113988>).
diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
index 19f1748ff9c..4ee12d501e8 100644
--- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
+++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
@@ -1,39 +1,57 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/detect-extra-ub.rs:26:20
+  --> $DIR/detect-extra-ub.rs:29:20
    |
 LL |     let _x: bool = transmute(3u8);
    |                    ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/detect-extra-ub.rs:32:21
+  --> $DIR/detect-extra-ub.rs:35:21
    |
 LL |     let _x: usize = transmute(&3u8);
-   |                     ^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                     ^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected an integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/detect-extra-ub.rs:38:30
+  --> $DIR/detect-extra-ub.rs:41:28
+   |
+LL |     let _x: PtrSizedEnum = transmute(&3u8);
+   |                            ^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered a pointer, but expected an integer
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:48:30
    |
 LL |     let _x: (usize, usize) = transmute(x);
-   |                              ^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |                              ^^^^^^^^^^^^ constructing invalid value at .0: encountered a pointer, but expected an integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/detect-extra-ub.rs:43:20
+  --> $DIR/detect-extra-ub.rs:54:20
    |
 LL |     let _x: &u32 = transmute(&[0u8; 4]);
    |                    ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/detect-extra-ub.rs:51:13
+  --> $DIR/detect-extra-ub.rs:62:13
    |
 LL |     let v = *addr_of!(data).cast::<UninhDiscriminant>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
 
-error: aborting due to 5 previous errors
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:82:16
+   |
+LL |     let _val = *(&mem as *const Align as *const [*const u8; 2]);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a partial pointer or a mix of pointers
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/issue-83182.rs b/tests/ui/consts/issue-83182.rs
deleted file mode 100644
index b62f903bdc2..00000000000
--- a/tests/ui/consts/issue-83182.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Strip out raw byte dumps to make comparison platform-independent:
-// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP"
-
-use std::mem;
-struct MyStr(str);
-const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-//~^ ERROR: it is undefined behavior to use this value
-fn main() {}
diff --git a/tests/ui/consts/issue-83182.stderr b/tests/ui/consts/issue-83182.stderr
deleted file mode 100644
index ca4e0f7aa02..00000000000
--- a/tests/ui/consts/issue-83182.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/issue-83182.rs:7:1
-   |
-LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
-   |
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-   = help: this code performed an operation that depends on the underlying bytes representing a pointer
-   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/issue-miri-1910.stderr b/tests/ui/consts/issue-miri-1910.stderr
index 67797e6fb5a..af0f77c6767 100644
--- a/tests/ui/consts/issue-miri-1910.stderr
+++ b/tests/ui/consts/issue-miri-1910.stderr
@@ -1,7 +1,7 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: unable to turn pointer into raw bytes
+   = note: unable to turn pointer into integer
    |
 note: inside `std::ptr::read::<u8>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs
index 4d12960b86b..5cda3c41152 100644
--- a/tests/ui/consts/miri_unleashed/ptr_arith.rs
+++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Zunleash-the-miri-inside-of-you
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, pointer_byte_offsets)]
 
 // During CTFE, we prevent pointer-to-int casts.
 // Pointer comparisons are prevented in the trait system.
@@ -15,7 +15,7 @@ static PTR_INT_TRANSMUTE: () = unsafe {
     let x: usize = std::mem::transmute(&0);
     let _v = x + 0;
     //~^ ERROR could not evaluate static initializer
-    //~| unable to turn pointer into raw bytes
+    //~| unable to turn pointer into integer
 };
 
 // I'd love to test pointer comparison, but that is not possible since
diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr
index 30fd3a55e85..25ca6bc4eaa 100644
--- a/tests/ui/consts/miri_unleashed/ptr_arith.stderr
+++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -8,7 +8,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ptr_arith.rs:16:14
    |
 LL |     let _v = x + 0;
-   |              ^ unable to turn pointer into raw bytes
+   |              ^ unable to turn pointer into integer
    |
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs
index 8babb68585d..43b9767db16 100644
--- a/tests/ui/consts/ptr_is_null.rs
+++ b/tests/ui/consts/ptr_is_null.rs
@@ -2,6 +2,7 @@
 // check-pass
 
 #![feature(const_ptr_is_null)]
+#![allow(useless_ptr_null_checks)]
 
 const FOO: &usize = &42;
 
diff --git a/tests/ui/did_you_mean/issue-114112.rs b/tests/ui/did_you_mean/issue-114112.rs
new file mode 100644
index 00000000000..0fde12ecd78
--- /dev/null
+++ b/tests/ui/did_you_mean/issue-114112.rs
@@ -0,0 +1,11 @@
+enum E<T> {
+    A(T)
+}
+
+fn main() {
+    match E::<i32>::A(1) {
+        E<i32>::A(v) => { //~ ERROR generic args in patterns require the turbofish syntax
+            println!("{v:?}");
+        },
+    }
+}
diff --git a/tests/ui/did_you_mean/issue-114112.stderr b/tests/ui/did_you_mean/issue-114112.stderr
new file mode 100644
index 00000000000..d76b5f72e30
--- /dev/null
+++ b/tests/ui/did_you_mean/issue-114112.stderr
@@ -0,0 +1,13 @@
+error: generic args in patterns require the turbofish syntax
+  --> $DIR/issue-114112.rs:7:10
+   |
+LL |         E<i32>::A(v) => {
+   |          ^
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |         E::<i32>::A(v) => {
+   |          ++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs
index dce94c9eab2..134ea25b75a 100644
--- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs
+++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs
@@ -1,7 +1,7 @@
 // edition:2018
-#![forbid(incomplete_features, unsafe_code)]
+#![forbid(internal_features, unsafe_code)]
 #![feature(unsafe_pin_internals)]
-//~^ ERROR the feature `unsafe_pin_internals` is incomplete and may not be safe to use
+//~^ ERROR the feature `unsafe_pin_internals` is internal to the compiler or standard library
 
 use core::{marker::PhantomPinned, pin::Pin};
 
diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr
index 4d0c931b404..39afbf2db7e 100644
--- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr
+++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr
@@ -1,14 +1,15 @@
-error: the feature `unsafe_pin_internals` is incomplete and may not be safe to use and/or cause compiler crashes
+error: the feature `unsafe_pin_internals` is internal to the compiler or standard library
   --> $DIR/feature-gate-unsafe_pin_internals.rs:3:12
    |
 LL | #![feature(unsafe_pin_internals)]
    |            ^^^^^^^^^^^^^^^^^^^^
    |
+   = note: using it is strongly discouraged
 note: the lint level is defined here
   --> $DIR/feature-gate-unsafe_pin_internals.rs:2:11
    |
-LL | #![forbid(incomplete_features, unsafe_code)]
-   |           ^^^^^^^^^^^^^^^^^^^
+LL | #![forbid(internal_features, unsafe_code)]
+   |           ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs
new file mode 100644
index 00000000000..0e894ef581c
--- /dev/null
+++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs
@@ -0,0 +1,17 @@
+#![feature(core_intrinsics)]
+#![feature(const_intrinsic_raw_eq)]
+
+const RAW_EQ_PADDING: bool = unsafe {
+    std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
+//~^ ERROR evaluation of constant value failed
+//~| requires initialized memory
+};
+
+const RAW_EQ_PTR: bool = unsafe {
+    std::intrinsics::raw_eq(&(&0), &(&1))
+//~^ ERROR evaluation of constant value failed
+//~| `raw_eq` on bytes with provenance
+};
+
+pub fn main() {
+}
diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr
index 56d5a48573e..4fc304cda60 100644
--- a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr
+++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr
@@ -1,9 +1,15 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/intrinsic-raw_eq-const-padding.rs:5:5
+  --> $DIR/intrinsic-raw_eq-const-bad.rs:5:5
    |
 LL |     std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
 
-error: aborting due to previous error
+error[E0080]: evaluation of constant value failed
+  --> $DIR/intrinsic-raw_eq-const-bad.rs:11:5
+   |
+LL |     std::intrinsics::raw_eq(&(&0), &(&1))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs
deleted file mode 100644
index a93d777d286..00000000000
--- a/tests/ui/intrinsics/intrinsic-raw_eq-const-padding.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(core_intrinsics)]
-#![feature(const_intrinsic_raw_eq)]
-
-const BAD_RAW_EQ_CALL: bool = unsafe {
-    std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
-//~^ ERROR evaluation of constant value failed
-};
-
-pub fn main() {
-}
diff --git a/tests/ui/lazy-type-alias/variance.rs b/tests/ui/lazy-type-alias/variance.rs
new file mode 100644
index 00000000000..f83215856b8
--- /dev/null
+++ b/tests/ui/lazy-type-alias/variance.rs
@@ -0,0 +1,38 @@
+// This is a regression test for issue #114221.
+// Check that we compute variances for lazy type aliases.
+
+// check-pass
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// [+] `A` is covariant over `'a`.
+struct A<'a>(Co<'a>);
+
+// [+] `Co` is covariant over `'a`.
+type Co<'a> = &'a ();
+
+fn co<'a>(x: A<'static>) {
+    let _: A<'a> = x;
+}
+
+// [-] `B` is contravariant over `'a`.
+struct B<'a>(Contra<'a>);
+
+// [-] `Contra` is contravariant over `'a`.
+type Contra<'a> = fn(&'a ());
+
+fn contra<'a>(x: B<'a>) {
+    let _: B<'static> = x;
+}
+
+struct C<T, U>(CoContra<T, U>);
+
+// [+, -] `CoContra` is covariant over `T` and contravariant over `U`.
+type CoContra<T, U> = Option<(T, fn(U))>;
+
+fn co_contra<'a>(x: C<&'static (), &'a ()>) -> C<&'a (), &'static ()> {
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/lint/fn_null_check.rs b/tests/ui/lint/fn_null_check.rs
deleted file mode 100644
index 7f01f2c4283..00000000000
--- a/tests/ui/lint/fn_null_check.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// check-pass
-
-fn main() {
-    let fn_ptr = main;
-
-    if (fn_ptr as *mut ()).is_null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *const u8).is_null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *const ()) == std::ptr::null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *const ()) == (0 as *const ()) {}
-    //~^ WARN function pointers are not nullable
-    if <*const _>::is_null(fn_ptr as *const ()) {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
-    //~^ WARN function pointers are not nullable
-    if (fn_ptr as fn() as *const ()).is_null() {}
-    //~^ WARN function pointers are not nullable
-
-    const ZPTR: *const () = 0 as *const _;
-    const NOT_ZPTR: *const () = 1 as *const _;
-
-    // unlike the uplifted clippy::fn_null_check lint we do
-    // not lint on them
-    if (fn_ptr as *const ()) == ZPTR {}
-    if (fn_ptr as *const ()) == NOT_ZPTR {}
-}
diff --git a/tests/ui/lint/fn_null_check.stderr b/tests/ui/lint/fn_null_check.stderr
deleted file mode 100644
index 0398c0da50f..00000000000
--- a/tests/ui/lint/fn_null_check.stderr
+++ /dev/null
@@ -1,67 +0,0 @@
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:6:8
-   |
-LL |     if (fn_ptr as *mut ()).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-   = note: `#[warn(incorrect_fn_null_checks)]` on by default
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:8:8
-   |
-LL |     if (fn_ptr as *const u8).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:10:8
-   |
-LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:12:8
-   |
-LL |     if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:14:8
-   |
-LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:16:8
-   |
-LL |     if <*const _>::is_null(fn_ptr as *const ()) {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:18:8
-   |
-LL |     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: function pointers are not nullable, so checking them for null will always return false
-  --> $DIR/fn_null_check.rs:20:8
-   |
-LL |     if (fn_ptr as fn() as *const ()).is_null() {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
-
-warning: 8 warnings emitted
-
diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs
new file mode 100644
index 00000000000..e677ea3094d
--- /dev/null
+++ b/tests/ui/lint/ptr_null_checks.rs
@@ -0,0 +1,76 @@
+// check-pass
+
+#![feature(ptr_from_ref)]
+
+use std::ptr;
+
+extern "C" fn c_fn() {}
+fn static_i32() -> &'static i32 { &1 }
+
+fn main() {
+    let fn_ptr = main;
+
+    // ------------- Function pointers ---------------
+    if (fn_ptr as *mut ()).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *const u8).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *const ()) == std::ptr::null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *const ()) == (0 as *const ()) {}
+    //~^ WARN function pointers are not nullable
+    if <*const _>::is_null(fn_ptr as *const ()) {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {}
+    //~^ WARN function pointers are not nullable
+    if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (fn_ptr as fn() as *const ()).is_null() {}
+    //~^ WARN function pointers are not nullable
+    if (c_fn as *const fn()).is_null() {}
+    //~^ WARN function pointers are not nullable
+
+    // ---------------- References ------------------
+    if (&mut 8 as *mut i32).is_null() {}
+    //~^ WARN references are not nullable
+    if ptr::from_mut(&mut 8).is_null() {}
+    //~^ WARN references are not nullable
+    if (&8 as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+    if ptr::from_ref(&8).is_null() {}
+    //~^ WARN references are not nullable
+    if ptr::from_ref(&8).cast_mut().is_null() {}
+    //~^ WARN references are not nullable
+    if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
+    //~^ WARN references are not nullable
+    if (&8 as *const i32) == std::ptr::null() {}
+    //~^ WARN references are not nullable
+    let ref_num = &8;
+    if (ref_num as *const i32) == std::ptr::null() {}
+    //~^ WARN references are not nullable
+    if (b"\0" as *const u8).is_null() {}
+    //~^ WARN references are not nullable
+    if ("aa" as *const str).is_null() {}
+    //~^ WARN references are not nullable
+    if (&[1, 2] as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+    if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {}
+    //~^ WARN references are not nullable
+    if (static_i32() as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+    if (&*{ static_i32() } as *const i32).is_null() {}
+    //~^ WARN references are not nullable
+
+    // ----------------------------------------------
+    const ZPTR: *const () = 0 as *const _;
+    const NOT_ZPTR: *const () = 1 as *const _;
+
+    // unlike the uplifted clippy::fn_null_check lint we do
+    // not lint on them
+    if (fn_ptr as *const ()) == ZPTR {}
+    if (fn_ptr as *const ()) == NOT_ZPTR {}
+}
diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr
new file mode 100644
index 00000000000..3cee1804b62
--- /dev/null
+++ b/tests/ui/lint/ptr_null_checks.stderr
@@ -0,0 +1,225 @@
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:14:8
+   |
+LL |     if (fn_ptr as *mut ()).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+   = note: `#[warn(useless_ptr_null_checks)]` on by default
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:16:8
+   |
+LL |     if (fn_ptr as *const u8).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:18:8
+   |
+LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:20:8
+   |
+LL |     if (fn_ptr as *mut ()) == std::ptr::null_mut() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:22:8
+   |
+LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:24:8
+   |
+LL |     if <*const _>::is_null(fn_ptr as *const ()) {}
+   |        ^^^^^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^
+   |                            |
+   |                            expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:26:8
+   |
+LL |     if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:28:8
+   |
+LL |     if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:30:8
+   |
+LL |     if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {}
+   |        ^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |          |
+   |          expression has type `fn() {main}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:32:8
+   |
+LL |     if (fn_ptr as fn() as *const ()).is_null() {}
+   |        ^--------------^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `fn()`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: function pointers are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:34:8
+   |
+LL |     if (c_fn as *const fn()).is_null() {}
+   |        ^----^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `extern "C" fn() {c_fn}`
+   |
+   = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:38:8
+   |
+LL |     if (&mut 8 as *mut i32).is_null() {}
+   |        ^------^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&mut i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:40:8
+   |
+LL |     if ptr::from_mut(&mut 8).is_null() {}
+   |        ^^^^^^^^^^^^^^------^^^^^^^^^^^
+   |                      |
+   |                      expression has type `&mut i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:42:8
+   |
+LL |     if (&8 as *const i32).is_null() {}
+   |        ^--^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:44:8
+   |
+LL |     if ptr::from_ref(&8).is_null() {}
+   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^
+   |                      |
+   |                      expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:46:8
+   |
+LL |     if ptr::from_ref(&8).cast_mut().is_null() {}
+   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^
+   |                      |
+   |                      expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:48:8
+   |
+LL |     if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
+   |        ^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:50:8
+   |
+LL |     if (&8 as *const i32) == std::ptr::null() {}
+   |        ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:53:8
+   |
+LL |     if (ref_num as *const i32) == std::ptr::null() {}
+   |        ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:55:8
+   |
+LL |     if (b"\0" as *const u8).is_null() {}
+   |        ^-----^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&[u8; 1]`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:57:8
+   |
+LL |     if ("aa" as *const str).is_null() {}
+   |        ^----^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&str`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:59:8
+   |
+LL |     if (&[1, 2] as *const i32).is_null() {}
+   |        ^-------^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&[i32; 2]`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:61:8
+   |
+LL |     if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {}
+   |        ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&mut [i32; 2]`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:63:8
+   |
+LL |     if (static_i32() as *const i32).is_null() {}
+   |        ^------------^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: references are not nullable, so checking them for null will always return false
+  --> $DIR/ptr_null_checks.rs:65:8
+   |
+LL |     if (&*{ static_i32() } as *const i32).is_null() {}
+   |        ^------------------^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         expression has type `&i32`
+
+warning: 25 warnings emitted
+
diff --git a/tests/ui/parser/issues/issue-114219.rs b/tests/ui/parser/issues/issue-114219.rs
new file mode 100644
index 00000000000..332258b628c
--- /dev/null
+++ b/tests/ui/parser/issues/issue-114219.rs
@@ -0,0 +1,4 @@
+fn main() {
+    async move {};
+    //~^ ERROR `async move` blocks are only allowed in Rust 2018 or later
+}
diff --git a/tests/ui/parser/issues/issue-114219.stderr b/tests/ui/parser/issues/issue-114219.stderr
new file mode 100644
index 00000000000..90dcdc42775
--- /dev/null
+++ b/tests/ui/parser/issues/issue-114219.stderr
@@ -0,0 +1,8 @@
+error: `async move` blocks are only allowed in Rust 2018 or later
+  --> $DIR/issue-114219.rs:2:5
+   |
+LL |     async move {};
+   |     ^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/issues/issue-22647.rs b/tests/ui/parser/issues/issue-22647.rs
index a6861410682..163cbc69ddd 100644
--- a/tests/ui/parser/issues/issue-22647.rs
+++ b/tests/ui/parser/issues/issue-22647.rs
@@ -1,5 +1,5 @@
 fn main() {
-    let caller<F> = |f: F|  //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<`
+    let caller<F> = |f: F|  //~ ERROR generic args in patterns require the turbofish syntax
     where F: Fn() -> i32
     {
         let x = f();
diff --git a/tests/ui/parser/issues/issue-22647.stderr b/tests/ui/parser/issues/issue-22647.stderr
index 89b454d1973..585e7026661 100644
--- a/tests/ui/parser/issues/issue-22647.stderr
+++ b/tests/ui/parser/issues/issue-22647.stderr
@@ -1,8 +1,13 @@
-error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<`
+error: generic args in patterns require the turbofish syntax
   --> $DIR/issue-22647.rs:2:15
    |
 LL |     let caller<F> = |f: F|
-   |               ^ expected one of `:`, `;`, `=`, `@`, or `|`
+   |               ^
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |     let caller::<F> = |f: F|
+   |               ++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/parser/issues/issue-22712.rs b/tests/ui/parser/issues/issue-22712.rs
index 774de9c7e64..92b12b8e193 100644
--- a/tests/ui/parser/issues/issue-22712.rs
+++ b/tests/ui/parser/issues/issue-22712.rs
@@ -3,7 +3,7 @@ struct Foo<B> {
 }
 
 fn bar() {
-    let Foo<Vec<u8>>  //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<`
+    let Foo<Vec<u8>> //~ ERROR generic args in patterns require the turbofish syntax
 }
 
 fn main() {}
diff --git a/tests/ui/parser/issues/issue-22712.stderr b/tests/ui/parser/issues/issue-22712.stderr
index 30fabac6564..7f9d99d8edf 100644
--- a/tests/ui/parser/issues/issue-22712.stderr
+++ b/tests/ui/parser/issues/issue-22712.stderr
@@ -1,8 +1,13 @@
-error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<`
+error: generic args in patterns require the turbofish syntax
   --> $DIR/issue-22712.rs:6:12
    |
 LL |     let Foo<Vec<u8>>
-   |            ^ expected one of `:`, `;`, `=`, `@`, or `|`
+   |            ^
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |     let Foo::<Vec<u8>>
+   |            ++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs
new file mode 100644
index 00000000000..155872f7a5d
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field.rs
@@ -0,0 +1,70 @@
+// compile-flags: --crate-type=lib
+
+macro_rules! field {
+    ($name:ident:$type:ty) => {
+        $name:$type
+    };
+}
+
+macro_rules! variant {
+    ($name:ident) => {
+        $name
+    }
+}
+
+struct Struct {
+    field!(bar:u128),
+    //~^ NOTE macros cannot expand to struct fields
+    //~| ERROR unexpected token: `!`
+    //~| NOTE unexpected token after this
+    a: u32,
+    b: u32,
+    field!(recovers:()), //~ NOTE macros cannot expand to struct fields
+    //~^ ERROR unexpected token: `!`
+    //~^^ NOTE unexpected token after this
+}
+
+enum EnumVariant {
+    variant!(whoops),
+    //~^ NOTE macros cannot expand to enum variants
+    //~| ERROR unexpected token: `!`
+    //~| NOTE unexpected token after this
+    U32,
+    F64,
+    variant!(recovers),
+    //~^ NOTE macros cannot expand to enum variants
+    //~| ERROR unexpected token: `!`
+    //~| NOTE unexpected token after this
+    Data {
+        field!(x:u32),
+        //~^ NOTE macros cannot expand to struct fields
+        //~| ERROR unexpected token: `!`
+        //~| NOTE unexpected token after this
+    }
+}
+
+enum EnumVariantField {
+    Named {
+        field!(oopsies:()),
+        //~^ NOTE macros cannot expand to struct fields
+        //~| ERROR unexpected token: `!`
+        //~| unexpected token after this
+        field!(oopsies2:()),
+        //~^ NOTE macros cannot expand to struct fields
+        //~| ERROR unexpected token: `!`
+        //~| unexpected token after this
+    },
+}
+
+union Union {
+    A: u32,
+    field!(oopsies:()),
+    //~^ NOTE macros cannot expand to union fields
+    //~| ERROR unexpected token: `!`
+    //~| unexpected token after this
+    B: u32,
+    field!(recovers:()),
+    //~^ NOTE macros cannot expand to union fields
+    //~| ERROR unexpected token: `!`
+    //~| unexpected token after this
+}
diff --git a/tests/ui/parser/macro/macro-expand-to-field.stderr b/tests/ui/parser/macro/macro-expand-to-field.stderr
new file mode 100644
index 00000000000..adcd032f5c0
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field.stderr
@@ -0,0 +1,74 @@
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:16:10
+   |
+LL |     field!(bar:u128),
+   |          ^ unexpected token after this
+   |
+   = note: macros cannot expand to struct fields
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:22:10
+   |
+LL |     field!(recovers:()),
+   |          ^ unexpected token after this
+   |
+   = note: macros cannot expand to struct fields
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:28:12
+   |
+LL |     variant!(whoops),
+   |            ^ unexpected token after this
+   |
+   = note: macros cannot expand to enum variants
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:34:12
+   |
+LL |     variant!(recovers),
+   |            ^ unexpected token after this
+   |
+   = note: macros cannot expand to enum variants
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:39:14
+   |
+LL |         field!(x:u32),
+   |              ^ unexpected token after this
+   |
+   = note: macros cannot expand to struct fields
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:48:14
+   |
+LL |         field!(oopsies:()),
+   |              ^ unexpected token after this
+   |
+   = note: macros cannot expand to struct fields
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:52:14
+   |
+LL |         field!(oopsies2:()),
+   |              ^ unexpected token after this
+   |
+   = note: macros cannot expand to struct fields
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:61:10
+   |
+LL |     field!(oopsies:()),
+   |          ^ unexpected token after this
+   |
+   = note: macros cannot expand to union fields
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:66:10
+   |
+LL |     field!(recovers:()),
+   |          ^ unexpected token after this
+   |
+   = note: macros cannot expand to union fields
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
new file mode 100644
index 00000000000..39d1d065ed9
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
@@ -0,0 +1,18 @@
+macro_rules! arm {
+    ($pattern:pat => $block:block) => {
+        $pattern => $block
+    };
+}
+
+fn main() {
+    let x = Some(1);
+    match x {
+        Some(1) => {},
+        arm!(None => {}),
+        //~^ NOTE macros cannot expand to match arms
+        //~| ERROR unexpected `,` in pattern
+        // doesn't recover
+        Some(2) => {},
+        _ => {},
+    };
+}
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
new file mode 100644
index 00000000000..1a5f4696858
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
@@ -0,0 +1,10 @@
+error: unexpected `,` in pattern
+  --> $DIR/macro-expand-to-match-arm.rs:11:25
+   |
+LL |         arm!(None => {}),
+   |                         ^
+   |
+   = note: macros cannot expand to match arms
+
+error: aborting due to previous error
+
diff --git a/tests/ui/parser/pat-lt-bracket-3.rs b/tests/ui/parser/pat-lt-bracket-3.rs
index a8bdfd3fa18..bd83fe8db4b 100644
--- a/tests/ui/parser/pat-lt-bracket-3.rs
+++ b/tests/ui/parser/pat-lt-bracket-3.rs
@@ -3,8 +3,7 @@ struct Foo<T>(T, T);
 impl<T> Foo<T> {
     fn foo(&self) {
         match *self {
-            Foo<T>(x, y) => {
-            //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<`
+            Foo<T>(x, y) => { //~ ERROR generic args in patterns require the turbofish syntax
               println!("Goodbye, World!")
             }
         }
diff --git a/tests/ui/parser/pat-lt-bracket-3.stderr b/tests/ui/parser/pat-lt-bracket-3.stderr
index bacf868e3c4..afdf1e9a557 100644
--- a/tests/ui/parser/pat-lt-bracket-3.stderr
+++ b/tests/ui/parser/pat-lt-bracket-3.stderr
@@ -1,8 +1,13 @@
-error: expected one of `=>`, `@`, `if`, or `|`, found `<`
+error: generic args in patterns require the turbofish syntax
   --> $DIR/pat-lt-bracket-3.rs:6:16
    |
 LL |             Foo<T>(x, y) => {
-   |                ^ expected one of `=>`, `@`, `if`, or `|`
+   |                ^
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |             Foo::<T>(x, y) => {
+   |                ++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/parser/pat-lt-bracket-4.rs b/tests/ui/parser/pat-lt-bracket-4.rs
index de314f6c641..6d348b68cd6 100644
--- a/tests/ui/parser/pat-lt-bracket-4.rs
+++ b/tests/ui/parser/pat-lt-bracket-4.rs
@@ -5,7 +5,7 @@ enum BtNode {
 
 fn main() {
     let y = match 10 {
-        Foo<T>::A(value) => value, //~ error: expected one of `=>`, `@`, `if`, or `|`, found `<`
+        Foo<T>::A(value) => value, //~ ERROR generic args in patterns require the turbofish syntax
         Foo<T>::B => 7,
     };
 }
diff --git a/tests/ui/parser/pat-lt-bracket-4.stderr b/tests/ui/parser/pat-lt-bracket-4.stderr
index 911c276b931..b71a5ad939e 100644
--- a/tests/ui/parser/pat-lt-bracket-4.stderr
+++ b/tests/ui/parser/pat-lt-bracket-4.stderr
@@ -1,8 +1,13 @@
-error: expected one of `=>`, `@`, `if`, or `|`, found `<`
+error: generic args in patterns require the turbofish syntax
   --> $DIR/pat-lt-bracket-4.rs:8:12
    |
 LL |         Foo<T>::A(value) => value,
-   |            ^ expected one of `=>`, `@`, `if`, or `|`
+   |            ^
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |         Foo::<T>::A(value) => value,
+   |            ++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/simd/intrinsic/generic-elements-pass.rs b/tests/ui/simd/intrinsic/generic-elements-pass.rs
index 3c913c0adfa..905c3b8d3cc 100644
--- a/tests/ui/simd/intrinsic/generic-elements-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-elements-pass.rs
@@ -22,9 +22,7 @@ extern "platform-intrinsic" {
     fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
     fn simd_extract<T, E>(x: T, idx: u32) -> E;
 
-    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
-    fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
-    fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
+    fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 }
 
 macro_rules! all_eq {
@@ -83,19 +81,19 @@ fn main() {
     let y4 = i32x4(140, 141, 142, 143);
     let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187);
     unsafe {
-        all_eq!(simd_shuffle2(x2, y2, const { [3u32, 0] }), i32x2(121, 20));
-        all_eq!(simd_shuffle4(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120));
-        all_eq!(simd_shuffle8(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }),
+        all_eq!(simd_shuffle(x2, y2, const { [3u32, 0] }), i32x2(121, 20));
+        all_eq!(simd_shuffle(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120));
+        all_eq!(simd_shuffle(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }),
                 i32x8(121, 20, 21, 120, 21, 120, 121, 20));
 
-        all_eq!(simd_shuffle2(x4, y4, const { [7u32, 2] }), i32x2(143, 42));
-        all_eq!(simd_shuffle4(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40));
-        all_eq!(simd_shuffle8(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }),
+        all_eq!(simd_shuffle(x4, y4, const { [7u32, 2] }), i32x2(143, 42));
+        all_eq!(simd_shuffle(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40));
+        all_eq!(simd_shuffle(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }),
                 i32x8(143, 42, 141, 40, 43, 142, 140, 41));
 
-        all_eq!(simd_shuffle2(x8, y8, const { [11u32, 5] }), i32x2(183, 85));
-        all_eq!(simd_shuffle4(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80));
-        all_eq!(simd_shuffle8(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }),
+        all_eq!(simd_shuffle(x8, y8, const { [11u32, 5] }), i32x2(183, 85));
+        all_eq!(simd_shuffle(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80));
+        all_eq!(simd_shuffle(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }),
                 i32x8(183, 85, 187, 80, 83, 180, 184, 81));
     }
 
diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs
index abde69163bd..0ff2203ec72 100644
--- a/tests/ui/simd/intrinsic/generic-elements.rs
+++ b/tests/ui/simd/intrinsic/generic-elements.rs
@@ -34,9 +34,7 @@ extern "platform-intrinsic" {
     fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
     fn simd_extract<T, E>(x: T, idx: u32) -> E;
 
-    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
-    fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
-    fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
+    fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 }
 
 fn main() {
@@ -51,27 +49,27 @@ fn main() {
         //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32`
 
         const IDX2: [u32; 2] = [0; 2];
-        simd_shuffle2::<i32, i32>(0, 0, IDX2);
+        simd_shuffle::<i32, _, i32>(0, 0, IDX2);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
         const IDX4: [u32; 4] = [0; 4];
-        simd_shuffle4::<i32, i32>(0, 0, IDX4);
+        simd_shuffle::<i32, _, i32>(0, 0, IDX4);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
         const IDX8: [u32; 8] = [0; 8];
-        simd_shuffle8::<i32, i32>(0, 0, IDX8);
+        simd_shuffle::<i32, _, i32>(0, 0, IDX8);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
-        simd_shuffle2::<_, f32x2>(x, x, IDX2);
+        simd_shuffle::<_, _, f32x2>(x, x, IDX2);
 //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
-        simd_shuffle4::<_, f32x4>(x, x, IDX4);
+        simd_shuffle::<_, _, f32x4>(x, x, IDX4);
 //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
-        simd_shuffle8::<_, f32x8>(x, x, IDX8);
+        simd_shuffle::<_, _, f32x8>(x, x, IDX8);
 //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
 
-        simd_shuffle2::<_, i32x8>(x, x, IDX2);
+        simd_shuffle::<_, _, i32x8>(x, x, IDX2);
         //~^ ERROR expected return type of length 2, found `i32x8` with length 8
-        simd_shuffle4::<_, i32x8>(x, x, IDX4);
+        simd_shuffle::<_, _, i32x8>(x, x, IDX4);
         //~^ ERROR expected return type of length 4, found `i32x8` with length 8
-        simd_shuffle8::<_, i32x2>(x, x, IDX8);
+        simd_shuffle::<_, _, i32x2>(x, x, IDX8);
         //~^ ERROR expected return type of length 8, found `i32x2` with length 2
     }
 }
diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr
index 5b423f7040f..115d9d4b3f3 100644
--- a/tests/ui/simd/intrinsic/generic-elements.stderr
+++ b/tests/ui/simd/intrinsic/generic-elements.stderr
@@ -1,74 +1,74 @@
 error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:46:9
+  --> $DIR/generic-elements.rs:44:9
    |
 LL |         simd_insert(0, 0, 0);
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64`
-  --> $DIR/generic-elements.rs:48:9
+  --> $DIR/generic-elements.rs:46:9
    |
 LL |         simd_insert(x, 0, 1.0);
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32`
-  --> $DIR/generic-elements.rs:50:9
+  --> $DIR/generic-elements.rs:48:9
    |
 LL |         simd_extract::<_, f32>(x, 0);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:54:9
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-elements.rs:52:9
    |
-LL |         simd_shuffle2::<i32, i32>(0, 0, IDX2);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<i32, _, i32>(0, 0, IDX2);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:57:9
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-elements.rs:55:9
    |
-LL |         simd_shuffle4::<i32, i32>(0, 0, IDX4);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<i32, _, i32>(0, 0, IDX4);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32`
-  --> $DIR/generic-elements.rs:60:9
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32`
+  --> $DIR/generic-elements.rs:58:9
    |
-LL |         simd_shuffle8::<i32, i32>(0, 0, IDX8);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<i32, _, i32>(0, 0, IDX8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
+  --> $DIR/generic-elements.rs:61:9
+   |
+LL |         simd_shuffle::<_, _, f32x2>(x, x, IDX2);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
   --> $DIR/generic-elements.rs:63:9
    |
-LL |         simd_shuffle2::<_, f32x2>(x, x, IDX2);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<_, _, f32x4>(x, x, IDX4);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
   --> $DIR/generic-elements.rs:65:9
    |
-LL |         simd_shuffle4::<_, f32x4>(x, x, IDX4);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<_, _, f32x8>(x, x, IDX8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
-  --> $DIR/generic-elements.rs:67:9
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8
+  --> $DIR/generic-elements.rs:68:9
    |
-LL |         simd_shuffle8::<_, f32x8>(x, x, IDX8);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<_, _, i32x8>(x, x, IDX2);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8
   --> $DIR/generic-elements.rs:70:9
    |
-LL |         simd_shuffle2::<_, i32x8>(x, x, IDX2);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<_, _, i32x8>(x, x, IDX4);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2
   --> $DIR/generic-elements.rs:72:9
    |
-LL |         simd_shuffle4::<_, i32x8>(x, x, IDX4);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2
-  --> $DIR/generic-elements.rs:74:9
-   |
-LL |         simd_shuffle8::<_, i32x2>(x, x, IDX8);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle::<_, _, i32x2>(x, x, IDX8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs
index 7221b3ab769..5ca684a9d78 100644
--- a/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs
+++ b/tests/ui/simd/intrinsic/inlining-issue67557-ice.rs
@@ -6,7 +6,7 @@
 #![feature(platform_intrinsics, repr_simd)]
 
 extern "platform-intrinsic" {
-    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
+    fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 }
 
 #[repr(simd)]
@@ -22,5 +22,5 @@ fn main() {
 #[inline(always)]
 unsafe fn inline_me() -> Simd2 {
     const IDX: [u32; 2] = [0, 3];
-    simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX)
+    simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX)
 }
diff --git a/tests/ui/simd/intrinsic/inlining-issue67557.rs b/tests/ui/simd/intrinsic/inlining-issue67557.rs
index 0d15427095a..5633ad70cd3 100644
--- a/tests/ui/simd/intrinsic/inlining-issue67557.rs
+++ b/tests/ui/simd/intrinsic/inlining-issue67557.rs
@@ -6,7 +6,7 @@
 #![feature(platform_intrinsics, repr_simd)]
 
 extern "platform-intrinsic" {
-    fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
+    fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 }
 
 #[repr(simd)]
@@ -16,7 +16,7 @@ struct Simd2(u8, u8);
 fn main() {
     unsafe {
         const IDX: [u32; 2] = [0, 1];
-        let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX);
+        let p_res: Simd2 = simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX);
         let a_res: Simd2 = inline_me();
 
         assert_10_11(p_res);
@@ -38,5 +38,5 @@ fn assert_10_13(x: Simd2) {
 #[inline(always)]
 unsafe fn inline_me() -> Simd2 {
     const IDX: [u32; 2] = [0, 3];
-    simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX)
+    simd_shuffle(Simd2(10, 11), Simd2(12, 13), IDX)
 }
diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.rs b/tests/ui/simd/shuffle-not-out-of-bounds.rs
index 0dee3a0e869..18939bcc5b4 100644
--- a/tests/ui/simd/shuffle-not-out-of-bounds.rs
+++ b/tests/ui/simd/shuffle-not-out-of-bounds.rs
@@ -29,12 +29,7 @@ struct u8x32([u8; 32]);
 struct u8x64([u8; 64]);
 
 extern "platform-intrinsic" {
-    pub fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
-    pub fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
-    pub fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
-    pub fn simd_shuffle16<T, U>(x: T, y: T, idx: [u32; 16]) -> U;
-    pub fn simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U;
-    pub fn simd_shuffle64<T, U>(x: T, y: T, idx: [u32; 64]) -> U;
+    pub fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 }
 
 // Test vectors by lane size. Since LLVM does not distinguish between a shuffle
@@ -58,22 +53,22 @@ macro_rules! test_shuffle_lanes {
         }
     }
 }
-//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic
-//~| ERROR: invalid monomorphization of `simd_shuffle4` intrinsic
-//~| ERROR: invalid monomorphization of `simd_shuffle8` intrinsic
-//~| ERROR: invalid monomorphization of `simd_shuffle16` intrinsic
-//~| ERROR: invalid monomorphization of `simd_shuffle32` intrinsic
-//~| ERROR: invalid monomorphization of `simd_shuffle64` intrinsic
+//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle` intrinsic
 // Because the test is mostly embedded in a macro, all the errors have the same origin point.
 // And unfortunately, standard comments, as in the UI test harness, disappear in macros!
 
 fn main() {
-    test_shuffle_lanes!(2, u8x2, simd_shuffle2);
-    test_shuffle_lanes!(4, u8x4, simd_shuffle4);
-    test_shuffle_lanes!(8, u8x8, simd_shuffle8);
-    test_shuffle_lanes!(16, u8x16, simd_shuffle16);
-    test_shuffle_lanes!(32, u8x32, simd_shuffle32);
-    test_shuffle_lanes!(64, u8x64, simd_shuffle64);
+    test_shuffle_lanes!(2, u8x2, simd_shuffle);
+    test_shuffle_lanes!(4, u8x4, simd_shuffle);
+    test_shuffle_lanes!(8, u8x8, simd_shuffle);
+    test_shuffle_lanes!(16, u8x16, simd_shuffle);
+    test_shuffle_lanes!(32, u8x32, simd_shuffle);
+    test_shuffle_lanes!(64, u8x64, simd_shuffle);
 
     extern "platform-intrinsic" {
         fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.stderr b/tests/ui/simd/shuffle-not-out-of-bounds.stderr
index 415f04d933f..59e5ab85866 100644
--- a/tests/ui/simd/shuffle-not-out-of-bounds.stderr
+++ b/tests/ui/simd/shuffle-not-out-of-bounds.stderr
@@ -1,71 +1,71 @@
-error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: shuffle index #0 is out of bounds (limit 4)
-  --> $DIR/shuffle-not-out-of-bounds.rs:56:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
+  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
 ...
-LL |     test_shuffle_lanes!(2, u8x2, simd_shuffle2);
-   |     ------------------------------------------- in this macro invocation
+LL |     test_shuffle_lanes!(2, u8x2, simd_shuffle);
+   |     ------------------------------------------ in this macro invocation
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: shuffle index #0 is out of bounds (limit 8)
-  --> $DIR/shuffle-not-out-of-bounds.rs:56:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 8)
+  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
 ...
-LL |     test_shuffle_lanes!(4, u8x4, simd_shuffle4);
-   |     ------------------------------------------- in this macro invocation
+LL |     test_shuffle_lanes!(4, u8x4, simd_shuffle);
+   |     ------------------------------------------ in this macro invocation
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: shuffle index #0 is out of bounds (limit 16)
-  --> $DIR/shuffle-not-out-of-bounds.rs:56:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 16)
+  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
 ...
-LL |     test_shuffle_lanes!(8, u8x8, simd_shuffle8);
-   |     ------------------------------------------- in this macro invocation
+LL |     test_shuffle_lanes!(8, u8x8, simd_shuffle);
+   |     ------------------------------------------ in this macro invocation
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle16` intrinsic: shuffle index #0 is out of bounds (limit 32)
-  --> $DIR/shuffle-not-out-of-bounds.rs:56:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 32)
+  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
 ...
-LL |     test_shuffle_lanes!(16, u8x16, simd_shuffle16);
-   |     ---------------------------------------------- in this macro invocation
+LL |     test_shuffle_lanes!(16, u8x16, simd_shuffle);
+   |     -------------------------------------------- in this macro invocation
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle32` intrinsic: shuffle index #0 is out of bounds (limit 64)
-  --> $DIR/shuffle-not-out-of-bounds.rs:56:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 64)
+  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
 ...
-LL |     test_shuffle_lanes!(32, u8x32, simd_shuffle32);
-   |     ---------------------------------------------- in this macro invocation
+LL |     test_shuffle_lanes!(32, u8x32, simd_shuffle);
+   |     -------------------------------------------- in this macro invocation
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle64` intrinsic: shuffle index #0 is out of bounds (limit 128)
-  --> $DIR/shuffle-not-out-of-bounds.rs:56:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 128)
+  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
 ...
-LL |     test_shuffle_lanes!(64, u8x64, simd_shuffle64);
-   |     ---------------------------------------------- in this macro invocation
+LL |     test_shuffle_lanes!(64, u8x64, simd_shuffle);
+   |     -------------------------------------------- in this macro invocation
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
-  --> $DIR/shuffle-not-out-of-bounds.rs:84:23
+  --> $DIR/shuffle-not-out-of-bounds.rs:79:23
    |
 LL |         let _: u8x2 = simd_shuffle(v, v, I);
    |                       ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/simd/shuffle.rs b/tests/ui/simd/shuffle.rs
index 461243d4892..838e31f8e41 100644
--- a/tests/ui/simd/shuffle.rs
+++ b/tests/ui/simd/shuffle.rs
@@ -8,7 +8,6 @@
 
 extern "platform-intrinsic" {
     fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
-    fn simd_shuffle16<T, U>(x: T, y: T, idx: [u32; 16]) -> U;
 }
 
 #[derive(Copy, Clone)]
@@ -16,7 +15,7 @@ extern "platform-intrinsic" {
 struct Simd<T, const N: usize>([T; N]);
 
 pub unsafe fn __shuffle_vector16<const IDX: [u32; 16], T, U>(x: T, y: T) -> U {
-    simd_shuffle16(x, y, IDX)
+    simd_shuffle(x, y, IDX)
 }
 
 fn main() {
diff --git a/tests/ui/suggestions/remove-question-symbol-with-paren.rs b/tests/ui/suggestions/remove-question-symbol-with-paren.rs
new file mode 100644
index 00000000000..c522793dbcb
--- /dev/null
+++ b/tests/ui/suggestions/remove-question-symbol-with-paren.rs
@@ -0,0 +1,9 @@
+// https://github.com/rust-lang/rust/issues/114392
+
+fn foo() -> Option<()> {
+    let x = Some(());
+    (x?)
+    //~^ ERROR `?` operator has incompatible types
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/remove-question-symbol-with-paren.stderr b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr
new file mode 100644
index 00000000000..39e35f733a1
--- /dev/null
+++ b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr
@@ -0,0 +1,22 @@
+error[E0308]: `?` operator has incompatible types
+  --> $DIR/remove-question-symbol-with-paren.rs:5:6
+   |
+LL |     (x?)
+   |      ^^ expected `Option<()>`, found `()`
+   |
+   = note: `?` operator cannot convert from `()` to `Option<()>`
+   = note:   expected enum `Option<()>`
+           found unit type `()`
+help: try removing this `?`
+   |
+LL -     (x?)
+LL +     (x)
+   |
+help: try wrapping the expression in `Some`
+   |
+LL |     (Some(x?))
+   |      +++++  +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
index 2c740ccc1ae..fdd8fa65bd0 100644
--- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
+++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
@@ -1,5 +1,7 @@
 #![feature(type_alias_impl_trait)]
 // check-pass
+// revisions: default edition2021
+//[edition2021] compile-flags: --edition 2021
 
 fn main() {
     type T = impl Copy;
diff --git a/triagebot.toml b/triagebot.toml
index d3dce34844c..3b2114855c1 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -490,7 +490,7 @@ cc = ["@nnethercote"]
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
-users_on_vacation = ["jyn514"]
+users_on_vacation = ["jyn514", "WaffleLapkin"]
 
 [assign.adhoc_groups]
 compiler-team = [