about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_abi/src/lib.rs35
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl3
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs112
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs142
-rw-r--r--compiler/rustc_ast_passes/messages.ftl5
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs23
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs16
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs125
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs25
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0203.md10
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl5
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs69
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs33
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs69
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs62
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs6
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp13
-rw-r--r--compiler/rustc_metadata/src/creader.rs286
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs7
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs44
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs6
-rw-r--r--compiler/rustc_parse/src/lexer/diagnostics.rs20
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs15
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs39
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs3
-rw-r--r--compiler/rustc_resolve/src/imports.rs38
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs3
-rw-r--r--compiler/rustc_resolve/src/lib.rs59
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--library/core/src/iter/adapters/zip.rs74
-rw-r--r--library/core/src/slice/mod.rs3
-rw-r--r--library/coretests/tests/iter/adapters/cloned.rs3
-rw-r--r--library/coretests/tests/iter/adapters/zip.rs119
-rw-r--r--src/bootstrap/README.md2
-rw-r--r--src/bootstrap/bootstrap.py7
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs7
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs52
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs330
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs55
-rw-r--r--src/bootstrap/src/core/builder/mod.rs3
-rw-r--r--src/bootstrap/src/core/builder/tests.rs29
-rw-r--r--src/bootstrap/src/lib.rs68
-rw-r--r--src/ci/github-actions/jobs.yml4
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md6
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ui.md20
-rw-r--r--src/doc/rustc/src/exploit-mitigations.md22
-rw-r--r--src/doc/rustc/src/platform-support/xtensa.md2
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/clean/utils.rs6
-rw-r--r--src/librustdoc/doctest.rs4
-rw-r--r--src/librustdoc/doctest/rust.rs2
-rw-r--r--src/librustdoc/formats/renderer.rs4
-rw-r--r--src/librustdoc/html/format.rs12
-rw-r--r--src/librustdoc/html/highlight.rs4
-rw-r--r--src/librustdoc/html/layout.rs1
-rw-r--r--src/librustdoc/html/markdown.rs4
-rw-r--r--src/librustdoc/html/render/context.rs84
-rw-r--r--src/librustdoc/html/render/mod.rs39
-rw-r--r--src/librustdoc/html/render/ordered_json.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs80
-rw-r--r--src/librustdoc/html/render/sidebar.rs2
-rw-r--r--src/librustdoc/html/render/sorted_template.rs3
-rw-r--r--src/librustdoc/json/conversions.rs20
-rw-r--r--src/librustdoc/json/mod.rs6
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs25
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs16
-rw-r--r--src/librustdoc/passes/strip_aliased_non_local.rs10
-rw-r--r--src/tools/compiletest/src/common.rs28
-rw-r--r--src/tools/compiletest/src/directives.rs12
-rw-r--r--src/tools/compiletest/src/runtest.rs7
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs53
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr5
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr5
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr5
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr5
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr5
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr7
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr7
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr7
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr5
-rw-r--r--src/tools/miri/tests/fail/read_from_trivial_switch.rs5
-rw-r--r--src/tools/miri/tests/fail/read_from_trivial_switch.stderr5
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-enum.rs3
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-enum.stderr5
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-pair.rs3
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-pair.stderr5
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-struct.stderr7
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs3
-rw-r--r--src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr5
-rw-r--r--src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs3
-rw-r--r--src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr5
-rw-r--r--src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr7
-rw-r--r--src/tools/miri/tests/fail/validity/invalid_int_op.stderr7
-rw-r--r--src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs2
-rw-r--r--src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr7
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-time.rs6
-rw-r--r--src/tools/opt-dist/src/environment.rs5
-rw-r--r--src/tools/opt-dist/src/exec.rs12
-rw-r--r--src/tools/opt-dist/src/main.rs122
-rw-r--r--src/tools/opt-dist/src/training.rs4
-rw-r--r--src/tools/tidy/src/features.rs35
-rw-r--r--src/tools/tidy/src/fluent_period.rs29
-rw-r--r--src/tools/tidy/src/fluent_used.rs2
-rw-r--r--src/tools/tidy/src/lib.rs7
-rw-r--r--src/tools/tidy/src/mir_opt_tests.rs31
-rw-r--r--src/tools/tidy/src/rustdoc_templates.rs2
-rw-r--r--src/tools/tidy/src/style.rs46
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs22
-rw-r--r--src/tools/tidy/src/ui_tests.rs43
-rw-r--r--src/tools/tidy/src/x_version.rs12
-rw-r--r--tests/codegen/enum/enum-discriminant-eq.rs223
-rw-r--r--tests/codegen/enum/enum-match.rs326
-rw-r--r--tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff48
-rw-r--r--tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff48
-rw-r--r--tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff48
-rw-r--r--tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff48
-rw-r--r--tests/mir-opt/inline_double_cycle.rs22
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/README.md13
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/array/array.check26
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/array/array.rs20
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check54
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs32
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/box/box.check12
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/box/box.rs18
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs18
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs31
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check12
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs19
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs20
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs18
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs18
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs18
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs23
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/union/union.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/union/union.rs20
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check10
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs14
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs28
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check18
-rw-r--r--tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs14
-rw-r--r--tests/run-make/link-eh-frame-terminator/rmake.rs1
-rw-r--r--tests/rustdoc/reexport/auxiliary/reexports-attrs.rs14
-rw-r--r--tests/rustdoc/reexport/reexport-attrs.rs20
-rw-r--r--tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs5
-rw-r--r--tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr20
-rw-r--r--tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs5
-rw-r--r--tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr23
-rw-r--r--tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr12
-rw-r--r--tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr12
-rw-r--r--tests/ui/consts/const-compare-bytes-ub.stderr8
-rw-r--r--tests/ui/consts/const-err-enum-discriminant.32bit.stderr13
-rw-r--r--tests/ui/consts/const-err-enum-discriminant.64bit.stderr13
-rw-r--r--tests/ui/consts/const-err-enum-discriminant.rs2
-rw-r--r--tests/ui/consts/const-err-enum-discriminant.stderr9
-rw-r--r--tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr12
-rw-r--r--tests/ui/consts/const-eval/ub-enum-overwrite.stderr6
-rw-r--r--tests/ui/consts/const-eval/ub-enum.rs3
-rw-r--r--tests/ui/consts/const-eval/ub-enum.stderr34
-rw-r--r--tests/ui/consts/const-eval/ub-nonnull.stderr6
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.rs3
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr46
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.rs7
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.stderr76
-rw-r--r--tests/ui/consts/const-eval/union-const-eval-field.rs1
-rw-r--r--tests/ui/consts/const-eval/union-const-eval-field.stderr12
-rw-r--r--tests/ui/consts/const-eval/union-ice.stderr18
-rw-r--r--tests/ui/consts/const-eval/union-ub.32bit.stderr6
-rw-r--r--tests/ui/consts/const-eval/union-ub.64bit.stderr6
-rw-r--r--tests/ui/contracts/contract-attributes-generics.rs6
-rw-r--r--tests/ui/contracts/contract-attributes-nest.rs4
-rw-r--r--tests/ui/contracts/contract-attributes-tail.rs4
-rw-r--r--tests/ui/contracts/contract-captures-via-closure-copy.rs2
-rw-r--r--tests/ui/contracts/contract-const-fn.rs4
-rw-r--r--tests/ui/contracts/contracts-ensures-early-fn-exit.rs6
-rw-r--r--tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs4
-rw-r--r--tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs4
-rw-r--r--tests/ui/contracts/internal_machinery/contract-intrinsics.rs4
-rw-r--r--tests/ui/contracts/internal_machinery/contract-lang-items.rs2
-rw-r--r--tests/ui/extern/extern-types-field-offset.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs20
-rw-r--r--tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr63
-rw-r--r--tests/ui/impl-trait/opt-out-bound-not-satisfied.rs4
-rw-r--r--tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr4
-rw-r--r--tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr4
-rw-r--r--tests/ui/issues/issue-37534.rs2
-rw-r--r--tests/ui/issues/issue-37534.stderr2
-rw-r--r--tests/ui/issues/issue-87199.rs8
-rw-r--r--tests/ui/issues/issue-87199.stderr8
-rw-r--r--tests/ui/mir/alignment/borrow_misaligned_field_projection.rs2
-rw-r--r--tests/ui/mir/alignment/misaligned_borrow.rs2
-rw-r--r--tests/ui/mir/alignment/misaligned_lhs.rs2
-rw-r--r--tests/ui/mir/alignment/misaligned_mut_borrow.rs2
-rw-r--r--tests/ui/mir/alignment/misaligned_rhs.rs2
-rw-r--r--tests/ui/mir/alignment/two_pointers.rs2
-rw-r--r--tests/ui/mir/enum/convert_non_integer_break.rs2
-rw-r--r--tests/ui/mir/enum/convert_non_integer_niche_break.rs2
-rw-r--r--tests/ui/mir/enum/negative_discr_break.rs2
-rw-r--r--tests/ui/mir/enum/niche_option_tuple_break.rs2
-rw-r--r--tests/ui/mir/enum/numbered_variants_break.rs2
-rw-r--r--tests/ui/mir/enum/option_with_bigger_niche_break.rs2
-rw-r--r--tests/ui/mir/enum/plain_no_data_break.rs2
-rw-r--r--tests/ui/mir/enum/single_with_repr_break.rs2
-rw-r--r--tests/ui/mir/enum/with_niche_int_break.rs2
-rw-r--r--tests/ui/mir/enum/wrap_break.rs2
-rw-r--r--tests/ui/mir/null/borrowed_mut_null.rs2
-rw-r--r--tests/ui/mir/null/borrowed_null.rs2
-rw-r--r--tests/ui/mir/null/borrowed_null_zst.rs2
-rw-r--r--tests/ui/mir/null/null_lhs.rs2
-rw-r--r--tests/ui/mir/null/null_rhs.rs2
-rw-r--r--tests/ui/mir/null/two_pointers.rs2
-rw-r--r--tests/ui/panics/panic-in-cleanup.rs2
-rw-r--r--tests/ui/panics/panic-in-ffi.rs2
-rw-r--r--tests/ui/panics/panic-in-message-fmt.rs2
-rw-r--r--tests/ui/panics/panic-main.rs12
-rw-r--r--tests/ui/parser/deli-ident-issue-2.rs2
-rw-r--r--tests/ui/parser/deli-ident-issue-2.stderr12
-rw-r--r--tests/ui/parser/issues/issue-104367.stderr1
-rw-r--r--tests/ui/parser/issues/issue-105209.rs2
-rw-r--r--tests/ui/parser/issues/issue-105209.stderr9
-rw-r--r--tests/ui/parser/issues/issue-62973.stderr6
-rw-r--r--tests/ui/parser/issues/issue-63116.stderr5
-rw-r--r--tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr12
-rw-r--r--tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs2
-rw-r--r--tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr12
-rw-r--r--tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs2
-rw-r--r--tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr12
-rw-r--r--tests/ui/parser/issues/issue-81827.stderr5
-rw-r--r--tests/ui/parser/issues/unnessary-error-issue-138401.rs6
-rw-r--r--tests/ui/parser/issues/unnessary-error-issue-138401.stderr12
-rw-r--r--tests/ui/parser/trait-object-trait-parens.rs6
-rw-r--r--tests/ui/parser/trait-object-trait-parens.stderr18
-rw-r--r--tests/ui/precondition-checks/alignment.rs2
-rw-r--r--tests/ui/precondition-checks/ascii-char-digit_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/assert_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/char-from_u32_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/copy-nonoverlapping.rs2
-rw-r--r--tests/ui/precondition-checks/copy.rs2
-rw-r--r--tests/ui/precondition-checks/layout.rs2
-rw-r--r--tests/ui/precondition-checks/nonnull.rs2
-rw-r--r--tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/nonzero-new_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/read_volatile.rs2
-rw-r--r--tests/ui/precondition-checks/replace.rs2
-rw-r--r--tests/ui/precondition-checks/slice-from-raw-parts-mut.rs2
-rw-r--r--tests/ui/precondition-checks/slice-from-raw-parts.rs2
-rw-r--r--tests/ui/precondition-checks/slice-get_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/slice-get_unchecked_mut.rs2
-rw-r--r--tests/ui/precondition-checks/str-get_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/str-get_unchecked_mut.rs2
-rw-r--r--tests/ui/precondition-checks/swap-nonoverlapping.rs2
-rw-r--r--tests/ui/precondition-checks/unchecked_add.rs2
-rw-r--r--tests/ui/precondition-checks/unchecked_mul.rs2
-rw-r--r--tests/ui/precondition-checks/unchecked_shl.rs2
-rw-r--r--tests/ui/precondition-checks/unchecked_shr.rs2
-rw-r--r--tests/ui/precondition-checks/unchecked_sub.rs2
-rw-r--r--tests/ui/precondition-checks/unreachable_unchecked.rs2
-rw-r--r--tests/ui/precondition-checks/vec-from-parts.rs2
-rw-r--r--tests/ui/precondition-checks/vec-from-raw-parts.rs2
-rw-r--r--tests/ui/precondition-checks/vec-set-len.rs2
-rw-r--r--tests/ui/precondition-checks/write_volatile.rs2
-rw-r--r--tests/ui/sanitizer/address.rs2
-rw-r--r--tests/ui/sanitizer/badfree.rs2
-rw-r--r--tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs2
-rw-r--r--tests/ui/sanitizer/thread.rs2
-rw-r--r--tests/ui/sanitizer/use-after-scope.rs2
-rw-r--r--tests/ui/sized-hierarchy/default-bound.rs4
-rw-r--r--tests/ui/sized-hierarchy/default-bound.stderr4
-rw-r--r--tests/ui/sized-hierarchy/default-supertrait.rs6
-rw-r--r--tests/ui/sized-hierarchy/default-supertrait.stderr19
-rw-r--r--tests/ui/sized-hierarchy/pointee-validation.rs20
-rw-r--r--tests/ui/sized-hierarchy/pointee-validation.stderr76
-rw-r--r--tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs4
-rw-r--r--tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr5
-rw-r--r--tests/ui/std/issue-81357-unsound-file-methods.rs2
-rw-r--r--tests/ui/suggestions/issue-94171.stderr4
-rw-r--r--tests/ui/trait-bounds/duplicate-relaxed-bounds.rs22
-rw-r--r--tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr47
-rw-r--r--tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs (renamed from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs)25
-rw-r--r--tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr (renamed from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr)40
-rw-r--r--tests/ui/trait-bounds/maybe-bound-has-path-args.rs2
-rw-r--r--tests/ui/trait-bounds/maybe-bound-has-path-args.stderr2
-rw-r--r--tests/ui/trait-bounds/maybe-bound-with-assoc.rs4
-rw-r--r--tests/ui/trait-bounds/maybe-bound-with-assoc.stderr4
-rw-r--r--tests/ui/trait-bounds/more_maybe_bounds.rs29
-rw-r--r--tests/ui/trait-bounds/more_maybe_bounds.stderr20
-rw-r--r--tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs3
-rw-r--r--tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr40
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs4
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr25
-rw-r--r--tests/ui/traits/maybe-polarity-pass.rs25
-rw-r--r--tests/ui/traits/maybe-polarity-pass.stderr20
-rw-r--r--tests/ui/traits/maybe-polarity-repeated.rs9
-rw-r--r--tests/ui/traits/maybe-polarity-repeated.stderr21
-rw-r--r--tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs18
-rw-r--r--tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr31
-rw-r--r--tests/ui/traits/wf-object/maybe-bound.rs18
-rw-r--r--tests/ui/traits/wf-object/maybe-bound.stderr48
-rw-r--r--tests/ui/traits/wf-object/only-maybe-bound.rs2
-rw-r--r--tests/ui/traits/wf-object/only-maybe-bound.stderr8
-rw-r--r--tests/ui/type/pattern_types/validity.rs4
-rw-r--r--tests/ui/type/pattern_types/validity.stderr12
-rw-r--r--tests/ui/typeck/issue-91334.stderr5
-rw-r--r--tests/ui/unsized/maybe-bounds-where.rs28
-rw-r--r--tests/ui/unsized/maybe-bounds-where.stderr70
-rw-r--r--tests/ui/unsized/relaxed-bounds-invalid-places.rs34
-rw-r--r--tests/ui/unsized/relaxed-bounds-invalid-places.stderr80
379 files changed, 4858 insertions, 2039 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index de4b5a46c81..5bd73502d98 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -43,7 +43,7 @@ use std::fmt;
 #[cfg(feature = "nightly")]
 use std::iter::Step;
 use std::num::{NonZeroUsize, ParseIntError};
-use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
+use std::ops::{Add, AddAssign, Deref, Mul, RangeFull, RangeInclusive, Sub};
 use std::str::FromStr;
 
 use bitflags::bitflags;
@@ -1391,12 +1391,45 @@ impl WrappingRange {
     }
 
     /// Returns `true` if `size` completely fills the range.
+    ///
+    /// Note that this is *not* the same as `self == WrappingRange::full(size)`.
+    /// Niche calculations can produce full ranges which are not the canonical one;
+    /// for example `Option<NonZero<u16>>` gets `valid_range: (..=0) | (1..)`.
     #[inline]
     fn is_full_for(&self, size: Size) -> bool {
         let max_value = size.unsigned_int_max();
         debug_assert!(self.start <= max_value && self.end <= max_value);
         self.start == (self.end.wrapping_add(1) & max_value)
     }
+
+    /// Checks whether this range is considered non-wrapping when the values are
+    /// interpreted as *unsigned* numbers of width `size`.
+    ///
+    /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is,
+    /// and `Err(..)` if the range is full so it depends how you think about it.
+    #[inline]
+    pub fn no_unsigned_wraparound(&self, size: Size) -> Result<bool, RangeFull> {
+        if self.is_full_for(size) { Err(..) } else { Ok(self.start <= self.end) }
+    }
+
+    /// Checks whether this range is considered non-wrapping when the values are
+    /// interpreted as *signed* numbers of width `size`.
+    ///
+    /// This is heavily dependent on the `size`, as `100..=200` does wrap when
+    /// interpreted as `i8`, but doesn't when interpreted as `i16`.
+    ///
+    /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is,
+    /// and `Err(..)` if the range is full so it depends how you think about it.
+    #[inline]
+    pub fn no_signed_wraparound(&self, size: Size) -> Result<bool, RangeFull> {
+        if self.is_full_for(size) {
+            Err(..)
+        } else {
+            let start: i128 = size.sign_extend(self.start);
+            let end: i128 = size.sign_extend(self.end);
+            Ok(start <= end)
+        }
+    }
 }
 
 impl fmt::Debug for WrappingRange {
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index c6472fd45fa..370b15d2871 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -127,9 +127,6 @@ ast_lowering_misplaced_impl_trait =
     `impl Trait` is not allowed in {$position}
     .note = `impl Trait` is only allowed in arguments and return types of functions and methods
 
-ast_lowering_misplaced_relax_trait_bound =
-    `?Trait` bounds are only permitted at the point where a type parameter is declared
-
 ast_lowering_never_pattern_with_body =
     a never pattern is always unreachable
     .label = this will never be executed
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index b444324ef91..83f3a976e83 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -325,13 +325,6 @@ pub(crate) struct MisplacedDoubleDot {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_lowering_misplaced_relax_trait_bound)]
-pub(crate) struct MisplacedRelaxTraitBound {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_lowering_match_arm_with_no_body)]
 pub(crate) struct MatchArmWithNoBody {
     #[primary_span]
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index abd70c7517c..ddf01b69e7f 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -16,14 +16,11 @@ use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 use tracing::instrument;
 
-use super::errors::{
-    InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
-    UnionWithDefault,
-};
+use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault};
 use super::stability::{enabled_names, gate_unstable_abi};
 use super::{
     AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
-    ResolverAstLoweringExt,
+    RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
 };
 
 pub(super) struct ItemLowerer<'a, 'hir> {
@@ -435,6 +432,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     |this| {
                         let bounds = this.lower_param_bounds(
                             bounds,
+                            RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::SuperTrait),
                             ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         );
                         let items = this.arena.alloc_from_iter(
@@ -455,6 +453,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     |this| {
                         this.lower_param_bounds(
                             bounds,
+                            RelaxedBoundPolicy::Allowed,
                             ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         )
                     },
@@ -940,6 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::TraitItemKind::Type(
                             this.lower_param_bounds(
                                 bounds,
+                                RelaxedBoundPolicy::Allowed,
                                 ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                             ),
                             ty,
@@ -1677,61 +1677,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
         assert!(self.impl_trait_defs.is_empty());
         assert!(self.impl_trait_bounds.is_empty());
 
-        // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
-        // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
-        // these into hir when we lower thee where clauses), but this makes it quite difficult to
-        // keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound`
-        // checks both param bounds and where clauses for `?Sized`.
-        for pred in &generics.where_clause.predicates {
-            let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else {
-                continue;
-            };
-            let compute_is_param = || {
-                // Check if the where clause type is a plain type parameter.
-                match self
-                    .resolver
-                    .get_partial_res(bound_pred.bounded_ty.id)
-                    .and_then(|r| r.full_res())
-                {
-                    Some(Res::Def(DefKind::TyParam, def_id))
-                        if bound_pred.bound_generic_params.is_empty() =>
-                    {
-                        generics
-                            .params
-                            .iter()
-                            .any(|p| def_id == self.local_def_id(p.id).to_def_id())
-                    }
-                    // Either the `bounded_ty` is not a plain type parameter, or
-                    // it's not found in the generic type parameters list.
-                    _ => false,
-                }
-            };
-            // We only need to compute this once per `WherePredicate`, but don't
-            // need to compute this at all unless there is a Maybe bound.
-            let mut is_param: Option<bool> = None;
-            for bound in &bound_pred.bounds {
-                if !matches!(
-                    *bound,
-                    GenericBound::Trait(PolyTraitRef {
-                        modifiers: TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. },
-                        ..
-                    })
-                ) {
-                    continue;
-                }
-                let is_param = *is_param.get_or_insert_with(compute_is_param);
-                if !is_param && !self.tcx.features().more_maybe_bounds() {
-                    self.tcx
-                        .sess
-                        .create_feature_err(
-                            MisplacedRelaxTraitBound { span: bound.span() },
-                            sym::more_maybe_bounds,
-                        )
-                        .emit();
-                }
-            }
-        }
-
         let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
             self.lower_generic_bound_predicate(
@@ -1741,6 +1686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 &param.bounds,
                 param.colon_span,
                 generics.span,
+                RelaxedBoundPolicy::Allowed,
                 itctx,
                 PredicateOrigin::GenericParam,
             )
@@ -1750,7 +1696,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 .where_clause
                 .predicates
                 .iter()
-                .map(|predicate| self.lower_where_predicate(predicate)),
+                .map(|predicate| self.lower_where_predicate(predicate, &generics.params)),
         );
 
         let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self
@@ -1827,6 +1773,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         bounds: &[GenericBound],
         colon_span: Option<Span>,
         parent_span: Span,
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
@@ -1835,7 +1782,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             return None;
         }
 
-        let bounds = self.lower_param_bounds(bounds, itctx);
+        let bounds = self.lower_param_bounds(bounds, rbp, itctx);
 
         let param_span = ident.span;
 
@@ -1887,7 +1834,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
         Some(hir::WherePredicate { hir_id, span, kind })
     }
 
-    fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
+    fn lower_where_predicate(
+        &mut self,
+        pred: &WherePredicate,
+        params: &[ast::GenericParam],
+    ) -> hir::WherePredicate<'hir> {
         let hir_id = self.lower_node_id(pred.id);
         let span = self.lower_span(pred.span);
         self.lower_attrs(hir_id, &pred.attrs, span);
@@ -1896,17 +1847,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 bound_generic_params,
                 bounded_ty,
                 bounds,
-            }) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
-                bound_generic_params: self
-                    .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
-                bounded_ty: self
-                    .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
-                bounds: self.lower_param_bounds(
-                    bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                ),
-                origin: PredicateOrigin::WhereClause,
-            }),
+            }) => {
+                let rbp = if bound_generic_params.is_empty() {
+                    RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params)
+                } else {
+                    RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::LateBoundVarsInScope)
+                };
+                hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
+                    bound_generic_params: self.lower_generic_params(
+                        bound_generic_params,
+                        hir::GenericParamSource::Binder,
+                    ),
+                    bounded_ty: self.lower_ty(
+                        bounded_ty,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    ),
+                    bounds: self.lower_param_bounds(
+                        bounds,
+                        rbp,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    ),
+                    origin: PredicateOrigin::WhereClause,
+                })
+            }
             WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
                 hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
                     lifetime: self.lower_lifetime(
@@ -1916,6 +1879,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     ),
                     bounds: self.lower_param_bounds(
                         bounds,
+                        RelaxedBoundPolicy::Allowed,
                         ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                     ),
                     in_where_clause: true,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1c96a375035..533ee9bff54 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -53,8 +53,8 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
 use rustc_hir::lints::DelayedLint;
 use rustc_hir::{
-    self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
-    LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
+    self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
+    LifetimeSyntax, ParamName, TraitCandidate,
 };
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::extension;
@@ -281,6 +281,24 @@ impl ResolverAstLowering {
     }
 }
 
+/// How relaxed bounds `?Trait` should be treated.
+///
+/// Relaxed bounds should only be allowed in places where we later
+/// (namely during HIR ty lowering) perform *sized elaboration*.
+#[derive(Clone, Copy, Debug)]
+enum RelaxedBoundPolicy<'a> {
+    Allowed,
+    AllowedIfOnTyParam(NodeId, &'a [ast::GenericParam]),
+    Forbidden(RelaxedBoundForbiddenReason),
+}
+
+#[derive(Clone, Copy, Debug)]
+enum RelaxedBoundForbiddenReason {
+    TraitObjectTy,
+    SuperTrait,
+    LateBoundVarsInScope,
+}
+
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -1084,10 +1102,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
                     hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
                 } else {
-                    // Desugar `AssocTy: Bounds` into an assoc type binding where the
-                    // later desugars into a trait predicate.
-                    let bounds = self.lower_param_bounds(bounds, itctx);
-
+                    // FIXME(#135229): These should be forbidden!
+                    let bounds =
+                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
                     hir::AssocItemConstraintKind::Bound { bounds }
                 }
             }
@@ -1216,6 +1233,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         span: t.span,
                         parens: ast::Parens::No,
                     },
+                    RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::TraitObjectTy),
                     itctx,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
@@ -1271,7 +1289,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     parenthesized: hir::GenericArgsParentheses::No,
                     span_ext: span,
                 });
-                let path = self.make_lang_item_qpath(LangItem::Pin, span, Some(args));
+                let path = self.make_lang_item_qpath(hir::LangItem::Pin, span, Some(args));
                 hir::TyKind::Path(path)
             }
             TyKind::FnPtr(f) => {
@@ -1332,7 +1350,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             // takes care of rejecting invalid modifier combinations and
                             // const trait bounds in trait object types.
                             GenericBound::Trait(ty) => {
-                                let trait_ref = this.lower_poly_trait_ref(ty, itctx);
+                                let trait_ref = this.lower_poly_trait_ref(
+                                    ty,
+                                    RelaxedBoundPolicy::Forbidden(
+                                        RelaxedBoundForbiddenReason::TraitObjectTy,
+                                    ),
+                                    itctx,
+                                );
                                 Some(trait_ref)
                             }
                             GenericBound::Outlives(lifetime) => {
@@ -1387,9 +1411,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                         path
                     }
-                    ImplTraitContext::InBinding => {
-                        hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx))
-                    }
+                    ImplTraitContext::InBinding => hir::TyKind::TraitAscription(
+                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx),
+                    ),
                     ImplTraitContext::FeatureGated(position, feature) => {
                         let guar = self
                             .tcx
@@ -1505,7 +1529,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
         self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| {
-            this.lower_param_bounds(bounds, itctx)
+            this.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx)
         })
     }
 
@@ -1799,10 +1823,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         match tpb {
-            GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)),
+            GenericBound::Trait(p) => {
+                hir::GenericBound::Trait(self.lower_poly_trait_ref(p, rbp, itctx))
+            }
             GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime(
                 lifetime,
                 LifetimeSource::OutlivesBound,
@@ -2017,19 +2044,91 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     #[instrument(level = "debug", skip(self))]
     fn lower_poly_trait_ref(
         &mut self,
-        p: &PolyTraitRef,
+        PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ }: &PolyTraitRef,
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
         let bound_generic_params =
-            self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
-        let trait_ref = self.lower_trait_ref(p.modifiers, &p.trait_ref, itctx);
-        let modifiers = self.lower_trait_bound_modifiers(p.modifiers);
+            self.lower_lifetime_binder(trait_ref.ref_id, bound_generic_params);
+        let trait_ref = self.lower_trait_ref(*modifiers, trait_ref, itctx);
+        let modifiers = self.lower_trait_bound_modifiers(*modifiers);
+
+        if let ast::BoundPolarity::Maybe(_) = modifiers.polarity {
+            self.validate_relaxed_bound(trait_ref, *span, rbp);
+        }
+
         hir::PolyTraitRef {
             bound_generic_params,
             modifiers,
             trait_ref,
-            span: self.lower_span(p.span),
+            span: self.lower_span(*span),
+        }
+    }
+
+    fn validate_relaxed_bound(
+        &self,
+        trait_ref: hir::TraitRef<'_>,
+        span: Span,
+        rbp: RelaxedBoundPolicy<'_>,
+    ) {
+        // Even though feature `more_maybe_bounds` bypasses the given policy and (currently) enables
+        // relaxed bounds in every conceivable position[^1], we don't want to advertise it to the user
+        // (via a feature gate) since it's super internal. Besides this, it'd be quite distracting.
+        //
+        // [^1]: Strictly speaking, this is incorrect (at the very least for `Sized`) because it's
+        //       no longer fully consistent with default trait elaboration in HIR ty lowering.
+
+        match rbp {
+            RelaxedBoundPolicy::Allowed => return,
+            RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => {
+                if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res())
+                    && let Res::Def(DefKind::TyParam, def_id) = res
+                    && params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id())
+                {
+                    return;
+                }
+                if self.tcx.features().more_maybe_bounds() {
+                    return;
+                }
+            }
+            RelaxedBoundPolicy::Forbidden(reason) => {
+                if self.tcx.features().more_maybe_bounds() {
+                    return;
+                }
+
+                match reason {
+                    RelaxedBoundForbiddenReason::TraitObjectTy => {
+                        self.dcx().span_err(
+                            span,
+                            "relaxed bounds are not permitted in trait object types",
+                        );
+                        return;
+                    }
+                    RelaxedBoundForbiddenReason::SuperTrait => {
+                        let mut diag = self.dcx().struct_span_err(
+                            span,
+                            "relaxed bounds are not permitted in supertrait bounds",
+                        );
+                        if let Some(def_id) = trait_ref.trait_def_id()
+                            && self.tcx.is_lang_item(def_id, hir::LangItem::Sized)
+                        {
+                            diag.note("traits are `?Sized` by default");
+                        }
+                        diag.emit();
+                        return;
+                    }
+                    RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
+                };
+            }
         }
+
+        self.dcx()
+            .struct_span_err(span, "this relaxed bound is not permitted here")
+            .with_note(
+                "in this context, relaxed bounds are only allowed on \
+                 type parameters defined by the closest item",
+            )
+            .emit();
     }
 
     fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
@@ -2040,17 +2139,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> hir::GenericBounds<'hir> {
-        self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
+        self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, rbp, itctx))
     }
 
     fn lower_param_bounds_mut(
         &mut self,
         bounds: &[GenericBound],
+        rbp: RelaxedBoundPolicy<'_>,
         itctx: ImplTraitContext,
     ) -> impl Iterator<Item = hir::GenericBound<'hir>> {
-        bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
+        bounds.iter().map(move |bound| self.lower_param_bound(bound, rbp, itctx))
     }
 
     #[instrument(level = "debug", skip(self), ret)]
@@ -2084,6 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             bounds,
             /* colon_span */ None,
             span,
+            RelaxedBoundPolicy::Allowed,
             ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index e419154d65d..af93d55c898 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -212,11 +212,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
 ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
     .help = use `auto trait Trait {"{}"}` instead
 
-ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
-
-ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
-    .note = traits are `?{$path_str}` by default
-
 ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
     .suggestion = reorder the parameters: lifetimes, then consts and types
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index c69250c0305..a08dae11153 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1381,29 +1381,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         match bound {
             GenericBound::Trait(trait_ref) => {
                 match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
-                    (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
-                        if !self.features.more_maybe_bounds() =>
-                    {
-                        self.sess
-                            .create_feature_err(
-                                errors::OptionalTraitSupertrait {
-                                    span: trait_ref.span,
-                                    path_str: pprust::path_to_string(&trait_ref.trait_ref.path),
-                                },
-                                sym::more_maybe_bounds,
-                            )
-                            .emit();
-                    }
-                    (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
-                        if !self.features.more_maybe_bounds() =>
-                    {
-                        self.sess
-                            .create_feature_err(
-                                errors::OptionalTraitObject { span: trait_ref.span },
-                                sym::more_maybe_bounds,
-                            )
-                            .emit();
-                    }
                     (
                         BoundKind::TraitObject,
                         BoundConstness::Always(_),
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index c1ebd025c7a..fd4b2528541 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -567,22 +567,6 @@ pub(crate) struct NestedLifetimes {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_optional_trait_supertrait)]
-#[note]
-pub(crate) struct OptionalTraitSupertrait {
-    #[primary_span]
-    pub span: Span,
-    pub path_str: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(ast_passes_optional_trait_object)]
-pub(crate) struct OptionalTraitObject {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_const_bound_trait_object)]
 pub(crate) struct ConstBoundTraitObject {
     #[primary_span]
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 8a3eb2ac845..86d9ddba4d2 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -41,9 +41,9 @@ impl AttributeKind {
             Fundamental { .. } => Yes,
             Ignore { .. } => No,
             Inline(..) => No,
-            LinkName { .. } => Yes,
+            LinkName { .. } => Yes, // Needed for rustdoc
             LinkOrdinal { .. } => No,
-            LinkSection { .. } => No,
+            LinkSection { .. } => Yes, // Needed for rustdoc
             LoopMatch(..) => No,
             MacroTransparency(..) => Yes,
             Marker(..) => No,
@@ -51,8 +51,8 @@ impl AttributeKind {
             MustUse { .. } => Yes,
             Naked(..) => No,
             NoImplicitPrelude(..) => No,
-            NoMangle(..) => No,
-            NonExhaustive(..) => Yes,
+            NoMangle(..) => Yes,      // Needed for rustdoc
+            NonExhaustive(..) => Yes, // Needed for rustdoc
             OmitGdbPrettyPrinterSection => No,
             Optimize(..) => No,
             ParenSugar(..) => No,
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index b0d191528a8..6a3fdb6ede1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -486,6 +486,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                 // value and the variant index match, since that's all `Niche` can encode.
 
                 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
+                let niche_start_const = bx.cx().const_uint_big(tag_llty, niche_start);
 
                 // We have a subrange `niche_start..=niche_end` inside `range`.
                 // If the value of the tag is inside this subrange, it's a
@@ -511,35 +512,88 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                     // } else {
                     //     untagged_variant
                     // }
-                    let niche_start = bx.cx().const_uint_big(tag_llty, niche_start);
-                    let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start);
+                    let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start_const);
                     let tagged_discr =
                         bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64);
                     (is_niche, tagged_discr, 0)
                 } else {
-                    // The special cases don't apply, so we'll have to go with
-                    // the general algorithm.
-                    let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start));
+                    // With multiple niched variants we'll have to actually compute
+                    // the variant index from the stored tag.
+                    //
+                    // However, there's still one small optimization we can often do for
+                    // determining *whether* a tag value is a natural value or a niched
+                    // variant. The general algorithm involves a subtraction that often
+                    // wraps in practice, making it tricky to analyse. However, in cases
+                    // where there are few enough possible values of the tag that it doesn't
+                    // need to wrap around, we can instead just look for the contiguous
+                    // tag values on the end of the range with a single comparison.
+                    //
+                    // For example, take the type `enum Demo { A, B, Untagged(bool) }`.
+                    // The `bool` is {0, 1}, and the two other variants are given the
+                    // tags {2, 3} respectively. That means the `tag_range` is
+                    // `[0, 3]`, which doesn't wrap as unsigned (nor as signed), so
+                    // we can test for the niched variants with just `>= 2`.
+                    //
+                    // That means we're looking either for the niche values *above*
+                    // the natural values of the untagged variant:
+                    //
+                    //             niche_start                  niche_end
+                    //                  |                           |
+                    //                  v                           v
+                    // MIN -------------+---------------------------+---------- MAX
+                    //         ^        |         is niche          |
+                    //         |        +---------------------------+
+                    //         |                                    |
+                    //   tag_range.start                      tag_range.end
+                    //
+                    // Or *below* the natural values:
+                    //
+                    //    niche_start              niche_end
+                    //         |                       |
+                    //         v                       v
+                    // MIN ----+-----------------------+---------------------- MAX
+                    //         |       is niche        |           ^
+                    //         +-----------------------+           |
+                    //         |                                   |
+                    //   tag_range.start                      tag_range.end
+                    //
+                    // With those two options and having the flexibility to choose
+                    // between a signed or unsigned comparison on the tag, that
+                    // covers most realistic scenarios. The tests have a (contrived)
+                    // example of a 1-byte enum with over 128 niched variants which
+                    // wraps both as signed as unsigned, though, and for something
+                    // like that we're stuck with the general algorithm.
+
+                    let tag_range = tag_scalar.valid_range(&dl);
+                    let tag_size = tag_scalar.size(&dl);
+                    let niche_end = u128::from(relative_max).wrapping_add(niche_start);
+                    let niche_end = tag_size.truncate(niche_end);
+
+                    let relative_discr = bx.sub(tag, niche_start_const);
                     let cast_tag = bx.intcast(relative_discr, cast_to, false);
-                    let is_niche = bx.icmp(
-                        IntPredicate::IntULE,
-                        relative_discr,
-                        bx.cx().const_uint(tag_llty, relative_max as u64),
-                    );
-
-                    // Thanks to parameter attributes and load metadata, LLVM already knows
-                    // the general valid range of the tag. It's possible, though, for there
-                    // to be an impossible value *in the middle*, which those ranges don't
-                    // communicate, so it's worth an `assume` to let the optimizer know.
-                    if niche_variants.contains(&untagged_variant)
-                        && bx.cx().sess().opts.optimize != OptLevel::No
-                    {
-                        let impossible =
-                            u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32());
-                        let impossible = bx.cx().const_uint(tag_llty, impossible);
-                        let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible);
-                        bx.assume(ne);
-                    }
+                    let is_niche = if tag_range.no_unsigned_wraparound(tag_size) == Ok(true) {
+                        if niche_start == tag_range.start {
+                            let niche_end_const = bx.cx().const_uint_big(tag_llty, niche_end);
+                            bx.icmp(IntPredicate::IntULE, tag, niche_end_const)
+                        } else {
+                            assert_eq!(niche_end, tag_range.end);
+                            bx.icmp(IntPredicate::IntUGE, tag, niche_start_const)
+                        }
+                    } else if tag_range.no_signed_wraparound(tag_size) == Ok(true) {
+                        if niche_start == tag_range.start {
+                            let niche_end_const = bx.cx().const_uint_big(tag_llty, niche_end);
+                            bx.icmp(IntPredicate::IntSLE, tag, niche_end_const)
+                        } else {
+                            assert_eq!(niche_end, tag_range.end);
+                            bx.icmp(IntPredicate::IntSGE, tag, niche_start_const)
+                        }
+                    } else {
+                        bx.icmp(
+                            IntPredicate::IntULE,
+                            relative_discr,
+                            bx.cx().const_uint(tag_llty, relative_max as u64),
+                        )
+                    };
 
                     (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
                 };
@@ -550,11 +604,24 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                     bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta))
                 };
 
-                let discr = bx.select(
-                    is_niche,
-                    tagged_discr,
-                    bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64),
-                );
+                let untagged_variant_const =
+                    bx.cx().const_uint(cast_to, u64::from(untagged_variant.as_u32()));
+
+                // Thanks to parameter attributes and load metadata, LLVM already knows
+                // the general valid range of the tag. It's possible, though, for there
+                // to be an impossible value *in the middle*, which those ranges don't
+                // communicate, so it's worth an `assume` to let the optimizer know.
+                // Most importantly, this means when optimizing a variant test like
+                // `SELECT(is_niche, complex, CONST) == CONST` it's ok to simplify that
+                // to `!is_niche` because the `complex` part can't possibly match.
+                if niche_variants.contains(&untagged_variant)
+                    && bx.cx().sess().opts.optimize != OptLevel::No
+                {
+                    let ne = bx.icmp(IntPredicate::IntNE, tagged_discr, untagged_variant_const);
+                    bx.assume(ne);
+                }
+
+                let discr = bx.select(is_niche, tagged_discr, untagged_variant_const);
 
                 // In principle we could insert assumes on the possible range of `discr`, but
                 // currently in LLVM this isn't worth it because the original `tag` will
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 3e880d02001..e00fb2c1eaf 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -2,17 +2,17 @@ use std::mem;
 
 use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg};
 use rustc_middle::mir::AssertKind;
-use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo};
+use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo, UndefinedBehaviorInfo};
 use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty::ConstInt;
 use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{ConstInt, TyCtxt};
 use rustc_span::{Span, Symbol};
 
 use super::CompileTimeMachine;
 use crate::errors::{self, FrameNote, ReportErrorExt};
 use crate::interpret::{
-    CtfeProvenance, ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType,
-    Pointer, err_inval, err_machine_stop,
+    CtfeProvenance, ErrorHandled, Frame, InterpCx, InterpErrorInfo, InterpErrorKind,
+    MachineStopType, Pointer, err_inval, err_machine_stop,
 };
 
 /// The CTFE machine has some custom error kinds.
@@ -163,7 +163,7 @@ pub fn get_span_and_frames<'tcx>(
 /// You can use it to add a stacktrace of current execution according to
 /// `get_span_and_frames` or just give context on where the const eval error happened.
 pub(super) fn report<'tcx, C, F>(
-    tcx: TyCtxt<'tcx>,
+    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
     error: InterpErrorKind<'tcx>,
     span: Span,
     get_span_and_frames: C,
@@ -173,6 +173,7 @@ where
     C: FnOnce() -> (Span, Vec<FrameNote>),
     F: FnOnce(&mut Diag<'_>, Span, Vec<FrameNote>),
 {
+    let tcx = ecx.tcx.tcx;
     // Special handling for certain errors
     match error {
         // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
@@ -198,6 +199,20 @@ where
                 InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_)
             );
 
+            if let InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(
+                Some((alloc_id, _access)),
+            )) = error
+            {
+                let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
+                let info = ecx.get_alloc_info(alloc_id);
+                let raw_bytes = errors::RawBytesNote {
+                    size: info.size.bytes(),
+                    align: info.align.bytes(),
+                    bytes,
+                };
+                err.subdiagnostic(raw_bytes);
+            }
+
             error.add_args(&mut err);
 
             mk(&mut err, span, frames);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index ce72d59b8b0..f584f6c948e 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -411,7 +411,7 @@ fn report_eval_error<'tcx>(
     let instance = with_no_trimmed_paths!(cid.instance.to_string());
 
     super::report(
-        *ecx.tcx,
+        ecx,
         error,
         DUMMY_SP,
         || super::get_span_and_frames(ecx.tcx, ecx.stack()),
@@ -451,7 +451,7 @@ fn report_validation_error<'tcx>(
         errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };
 
     crate::const_eval::report(
-        *ecx.tcx,
+        ecx,
         error,
         DUMMY_SP,
         || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()),
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 7a73d70fc85..de4fbc7b475 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -17,6 +17,7 @@ use super::{
     throw_ub_custom,
 };
 use crate::fluent_generated as fluent;
+use crate::interpret::Writeable;
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn cast(
@@ -358,7 +359,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     fn unsize_into_ptr(
         &mut self,
         src: &OpTy<'tcx, M::Provenance>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
         // The pointee types
         source_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
@@ -455,7 +456,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         &mut self,
         src: &OpTy<'tcx, M::Provenance>,
         cast_ty: TyAndLayout<'tcx>,
-        dest: &PlaceTy<'tcx, M::Provenance>,
+        dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
         match (src.layout.ty.kind(), cast_ty.ty.kind()) {
@@ -496,7 +497,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     self.cur_span(),
                     "unsize_into: invalid conversion: {:?} -> {:?}",
                     src.layout,
-                    dest.layout
+                    dest.layout()
                 )
             }
         }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 62f591ceaa9..693b3782960 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -394,7 +394,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         interp_ok(try_validation!(
             self.ecx.read_immediate(val),
             self.path,
-            Ub(InvalidUninitBytes(None)) =>
+            Ub(InvalidUninitBytes(_)) =>
                 Uninit { expected },
             // The `Unsup` cases can only occur during CTFE
             Unsup(ReadPointerAsInt(_)) =>
diff --git a/compiler/rustc_error_codes/src/error_codes/E0203.md b/compiler/rustc_error_codes/src/error_codes/E0203.md
index 1edb519275f..a4dceedbf1f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0203.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0203.md
@@ -1,15 +1,15 @@
-Having multiple relaxed default bounds is unsupported.
+Having duplicate relaxed default bounds is unsupported.
 
 Erroneous code example:
 
 ```compile_fail,E0203
-struct Bad<T: ?Sized + ?Send>{
-    inner: T
+struct Bad<T: ?Sized + ?Sized>{
+    inner: T,
 }
 ```
 
-Here the type `T` cannot have a relaxed bound for multiple default traits
-(`Sized` and `Send`). This can be fixed by only using one relaxed bound.
+Here the type parameter `T` cannot have duplicate relaxed bounds for default
+trait `Sized`. This can be fixed by only using one relaxed bound:
 
 ```
 struct Good<T: ?Sized>{
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index a128f8d31a1..96c7ba6ed27 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1421,7 +1421,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
     ///
     /// See `emit` and `delay_as_bug` for details.
     #[track_caller]
-    pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
+    pub fn emit_unless_delay(mut self, delay: bool) -> G::EmitResult {
         if delay {
             self.downgrade_to_delayed_bug();
         }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index e38ca9e80ce..2428c1aa29f 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -371,9 +371,6 @@ hir_analysis_missing_type_params =
         *[other] parameters
     } must be specified on the object type
 
-hir_analysis_multiple_relaxed_default_bounds =
-    type parameter has more than one relaxed default bound, only one is supported
-
 hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
 
 hir_analysis_must_implement_not_function = not a function
@@ -448,8 +445,6 @@ hir_analysis_parenthesized_fn_trait_expansion =
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
 
-hir_analysis_pointee_sized_trait_object = `PointeeSized` cannot be used with trait objects
-
 hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
     .label = `Self` is not a generic argument, but an alias to the type of the {$what}
 
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 87db80f2423..e24426f9fed 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1173,7 +1173,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
             bounds_span,
             where_span,
         })
-        .emit_unless(delay);
+        .emit_unless_delay(delay);
 
     Err(reported)
 }
@@ -1481,7 +1481,7 @@ fn compare_self_type<'tcx>(
             } else {
                 err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
             }
-            return Err(err.emit_unless(delay));
+            return Err(err.emit_unless_delay(delay));
         }
 
         (true, false) => {
@@ -1502,7 +1502,7 @@ fn compare_self_type<'tcx>(
                 err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
             }
 
-            return Err(err.emit_unless(delay));
+            return Err(err.emit_unless_delay(delay));
         }
     }
 
@@ -1662,7 +1662,7 @@ fn compare_number_of_generics<'tcx>(
                 err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
             }
 
-            let reported = err.emit_unless(delay);
+            let reported = err.emit_unless_delay(delay);
             err_occurred = Some(reported);
         }
     }
@@ -1745,7 +1745,7 @@ fn compare_number_of_method_arguments<'tcx>(
             ),
         );
 
-        return Err(err.emit_unless(delay));
+        return Err(err.emit_unless_delay(delay));
     }
 
     Ok(())
@@ -1872,7 +1872,7 @@ fn compare_synthetic_generics<'tcx>(
                     );
                 };
             }
-            error_found = Some(err.emit_unless(delay));
+            error_found = Some(err.emit_unless_delay(delay));
         }
     }
     if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
@@ -1974,7 +1974,7 @@ fn compare_generic_param_kinds<'tcx>(
             err.span_label(impl_header_span, "");
             err.span_label(param_impl_span, make_param_message("found", param_impl));
 
-            let reported = err.emit_unless(delay);
+            let reported = err.emit_unless_delay(delay);
             return Err(reported);
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index f2f1560d8b2..cc53919626e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -267,20 +267,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         match predicate.kind {
             hir::WherePredicateKind::BoundPredicate(bound_pred) => {
                 let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
-
                 let bound_vars = tcx.late_bound_vars(predicate.hir_id);
-                // Keep the type around in a dummy predicate, in case of no bounds.
-                // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
-                // is still checked for WF.
+
+                // This is a `where Ty:` (sic!).
                 if bound_pred.bounds.is_empty() {
                     if let ty::Param(_) = ty.kind() {
-                        // This is a `where T:`, which can be in the HIR from the
-                        // transformation that moves `?Sized` to `T`'s declaration.
-                        // We can skip the predicate because type parameters are
-                        // trivially WF, but also we *should*, to avoid exposing
-                        // users who never wrote `where Type:,` themselves, to
-                        // compiler/tooling bugs from not handling WF predicates.
+                        // We can skip the predicate because type parameters are trivially WF.
                     } else {
+                        // Keep the type around in a dummy predicate. That way, it's not a complete
+                        // noop (see #53696) and `Ty` is still checked for WF.
+
                         let span = bound_pred.bounded_ty.span;
                         let predicate = ty::Binder::bind_with_vars(
                             ty::ClauseKind::WellFormed(ty.into()),
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 77e63e38c8c..eb3492f5de6 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -2495,7 +2495,7 @@ fn deny_non_region_late_bound(
             format!("late-bound {what} parameter not allowed on {where_}"),
         );
 
-        let guar = diag.emit_unless(!tcx.features().non_lifetime_binders() || !first);
+        let guar = diag.emit_unless_delay(!tcx.features().non_lifetime_binders() || !first);
 
         first = false;
         *arg = ResolvedArg::Error(guar);
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index fbd21f8b100..26a98722b34 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -280,13 +280,6 @@ pub(crate) struct CopyImplOnTypeWithDtor {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)]
-pub(crate) struct MultipleRelaxedDefaultBounds {
-    #[primary_span]
-    pub spans: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)]
 pub(crate) struct CopyImplOnNonAdt {
     #[primary_span]
@@ -320,13 +313,6 @@ pub(crate) struct TraitObjectDeclaredWithNoTraits {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_pointee_sized_trait_object)]
-pub(crate) struct PointeeSizedTraitObject {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_ambiguous_lifetime_bound, code = E0227)]
 pub(crate) struct AmbiguousLifetimeBound {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 9a752aeccdd..d7a827c649d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -6,7 +6,7 @@ use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
-use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
+use rustc_hir::{AmbigArg, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -85,17 +85,17 @@ fn search_bounds_for<'tcx>(
     }
 }
 
-fn collect_unbounds<'tcx>(
+fn collect_relaxed_bounds<'tcx>(
     hir_bounds: &'tcx [hir::GenericBound<'tcx>],
     self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
 ) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> {
-    let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
+    let mut relaxed_bounds: SmallVec<[_; 1]> = SmallVec::new();
     search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
         if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) {
-            unbounds.push(ptr);
+            relaxed_bounds.push(ptr);
         }
     });
-    unbounds
+    relaxed_bounds
 }
 
 fn collect_bounds<'a, 'tcx>(
@@ -124,13 +124,13 @@ fn collect_sizedness_bounds<'tcx>(
     self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
     span: Span,
 ) -> CollectedSizednessBounds {
-    let sized_did = tcx.require_lang_item(LangItem::Sized, span);
+    let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span);
     let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did);
 
-    let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
+    let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span);
     let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did);
 
-    let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+    let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span);
     let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did);
 
     CollectedSizednessBounds { sized, meta_sized, pointee_sized }
@@ -151,24 +151,6 @@ fn add_trait_bound<'tcx>(
 }
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    /// Skip `PointeeSized` bounds.
-    ///
-    /// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there
-    /// is actually the absence of any bounds. This avoids limitations around non-global where
-    /// clauses being preferred over item bounds (where `PointeeSized` bounds would be
-    /// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is
-    /// added to some items.
-    pub(crate) fn should_skip_sizedness_bound<'hir>(
-        &self,
-        bound: &'hir hir::GenericBound<'tcx>,
-    ) -> bool {
-        bound
-            .trait_ref()
-            .and_then(|tr| tr.trait_def_id())
-            .map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized))
-            .unwrap_or(false)
-    }
-
     /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type.
     ///
     /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit
@@ -193,8 +175,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             return;
         }
 
-        let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
-        let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+        let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span);
+        let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span);
 
         // If adding sizedness bounds to a trait, then there are some relevant early exits
         if let Some(trait_did) = trait_did {
@@ -209,9 +191,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 return;
             }
         } else {
-            // Report invalid unbounds on sizedness-bounded generic parameters.
-            let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates);
-            self.check_and_report_invalid_unbounds_on_param(unbounds);
+            // Report invalid relaxed bounds.
+            // FIXME: Since we only call this validation function here in this function, we only
+            //        fully validate relaxed bounds in contexts where we perform
+            //        "sized elaboration". In most cases that doesn't matter because we *usually*
+            //        reject such relaxed bounds outright during AST lowering.
+            //        However, this can easily get out of sync! Ideally, we would perform this step
+            //        where we are guaranteed to catch *all* bounds like in
+            //        `Self::lower_poly_trait_ref`. List of concrete issues:
+            //        FIXME(more_maybe_bounds): We don't call this for e.g., trait object tys or
+            //                                  supertrait bounds!
+            //        FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however,
+            //                                       AST lowering should reject them outright.
+            //        FIXME(associated_type_bounds): We don't call this for them. However, AST
+            //                                       lowering should reject them outright (#135229).
+            let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
+            self.check_and_report_invalid_relaxed_bounds(bounds);
         }
 
         let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
@@ -231,7 +226,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             } else {
                 // If there are no explicit sizedness bounds on a parameter then add a default
                 // `Sized` bound.
-                let sized_did = tcx.require_lang_item(LangItem::Sized, span);
+                let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span);
                 add_trait_bound(tcx, bounds, self_ty, sized_did, span);
             }
         }
@@ -463,10 +458,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         'tcx: 'hir,
     {
         for hir_bound in hir_bounds {
-            if self.should_skip_sizedness_bound(hir_bound) {
-                continue;
-            }
-
             // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`,
             // we skip over any traits that don't define the given associated type.
             if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter {
@@ -482,12 +473,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             match hir_bound {
                 hir::GenericBound::Trait(poly_trait_ref) => {
-                    let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
                     let _ = self.lower_poly_trait_ref(
-                        &poly_trait_ref.trait_ref,
-                        poly_trait_ref.span,
-                        constness,
-                        polarity,
+                        poly_trait_ref,
                         param_ty,
                         bounds,
                         predicate_filter,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 364ad38556b..76bb59e3f09 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -2,7 +2,6 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
-use rustc_hir::LangItem;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
 use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
@@ -18,9 +17,7 @@ use tracing::{debug, instrument};
 
 use super::HirTyLowerer;
 use crate::errors::SelfInTypeAlias;
-use crate::hir_ty_lowering::{
-    GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
-};
+use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Lower a trait object type from the HIR to our internal notion of a type.
@@ -38,24 +35,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         let mut user_written_bounds = Vec::new();
         let mut potential_assoc_types = Vec::new();
-        for trait_bound in hir_bounds.iter() {
-            if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
-                continue;
-            }
-            if let GenericArgCountResult {
-                correct:
-                    Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
-                ..
-            } = self.lower_poly_trait_ref(
-                &trait_bound.trait_ref,
-                trait_bound.span,
-                trait_bound.modifiers.constness,
-                hir::BoundPolarity::Positive,
+        for poly_trait_ref in hir_bounds.iter() {
+            let result = self.lower_poly_trait_ref(
+                poly_trait_ref,
                 dummy_self,
                 &mut user_written_bounds,
                 PredicateFilter::SelfOnly,
-            ) {
-                potential_assoc_types.extend(cur_potential_assoc_types);
+            );
+            if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
+                potential_assoc_types.extend(invalid_args);
             }
         }
 
@@ -81,13 +69,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let guar = self.report_trait_object_addition_traits(&regular_traits);
             return Ty::new_error(tcx, guar);
         }
-        // We don't support `PointeeSized` principals
-        let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
-        if regular_traits.iter().any(|(pred, _)| pred.def_id() == pointee_sized_did) {
-            let guar = self.report_pointee_sized_trait_object(span);
-            return Ty::new_error(tcx, guar);
-        }
-
         // Don't create a dyn trait if we have errors in the principal.
         if let Err(guar) = regular_traits.error_reported() {
             return Ty::new_error(tcx, guar);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 5d85a3f8455..287a5532f01 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -8,7 +8,7 @@ use rustc_errors::{
 };
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef};
+use rustc_hir::{self as hir, HirId, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -29,59 +29,54 @@ use tracing::debug;
 use super::InherentAssocCandidate;
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
-    ParenthesizedFnTraitExpansion, PointeeSizedTraitObject, TraitObjectDeclaredWithNoTraits,
+    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    /// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits.
-    pub(crate) fn check_and_report_invalid_unbounds_on_param(
+    /// Check for duplicate relaxed bounds and relaxed bounds of non-default traits.
+    pub(crate) fn check_and_report_invalid_relaxed_bounds(
         &self,
-        unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
+        relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
     ) {
         let tcx = self.tcx();
 
-        let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
+        let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
 
-        let mut unique_bounds = FxIndexSet::default();
-        let mut seen_repeat = false;
-        for unbound in &unbounds {
-            if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res {
-                seen_repeat |= !unique_bounds.insert(unbound_def_id);
+        for bound in &relaxed_bounds {
+            if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
+                grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
             }
         }
 
-        if unbounds.len() > 1 {
-            let err = errors::MultipleRelaxedDefaultBounds {
-                spans: unbounds.iter().map(|ptr| ptr.span).collect(),
-            };
-
-            if seen_repeat {
-                tcx.dcx().emit_err(err);
-            } else if !tcx.features().more_maybe_bounds() {
-                tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit();
-            };
+        for (trait_def_id, spans) in grouped_bounds {
+            if spans.len() > 1 {
+                let name = tcx.item_name(trait_def_id);
+                self.dcx()
+                    .struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
+                    .with_code(E0203)
+                    .emit();
+            }
         }
 
-        for unbound in unbounds {
-            if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res
-                && ((did == sized_did) || tcx.is_default_trait(did))
+        let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
+
+        for bound in relaxed_bounds {
+            if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res
+                && (def_id == sized_def_id || tcx.is_default_trait(def_id))
             {
                 continue;
             }
-
-            let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
-                true => "`?Sized` and `experimental_default_bounds`",
-                false => "`?Sized`",
-            };
             self.dcx().span_err(
-                unbound.span,
-                format!(
-                    "relaxing a default bound only does something for {}; all other traits are \
-                     not bound by default",
-                    unbound_traits
-                ),
+                bound.span,
+                if tcx.sess.opts.unstable_opts.experimental_default_bounds
+                    || tcx.features().more_maybe_bounds()
+                {
+                    "bound modifier `?` can only be applied to default traits like `Sized`"
+                } else {
+                    "bound modifier `?` can only be applied to `Sized`"
+                },
             );
         }
     }
@@ -1410,10 +1405,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
     }
-
-    pub(super) fn report_pointee_sized_trait_object(&self, span: Span) -> ErrorGuaranteed {
-        self.dcx().emit_err(PointeeSizedTraitObject { span })
-    }
 }
 
 /// Emit an error for the given associated item constraint.
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 8c7c3750865..fc519c194bb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -570,7 +570,7 @@ pub(crate) fn check_generic_arg_count(
                     gen_args,
                     def_id,
                 ))
-                .emit_unless(all_params_are_binded)
+                .emit_unless_delay(all_params_are_binded)
         });
 
         Err(reported)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index a5bd7c1a34a..78794cd8eb6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -747,18 +747,46 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
     /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`.
     /// The lowered poly-trait-ref will track this binder explicitly, however.
-    #[instrument(level = "debug", skip(self, span, constness, bounds))]
+    #[instrument(level = "debug", skip(self, bounds))]
     pub(crate) fn lower_poly_trait_ref(
         &self,
-        trait_ref: &hir::TraitRef<'tcx>,
-        span: Span,
-        constness: hir::BoundConstness,
-        polarity: hir::BoundPolarity,
+        poly_trait_ref: &hir::PolyTraitRef<'tcx>,
         self_ty: Ty<'tcx>,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         predicate_filter: PredicateFilter,
     ) -> GenericArgCountResult {
+        let tcx = self.tcx();
+
+        // We use the *resolved* bound vars later instead of the HIR ones since the former
+        // also include the bound vars of the overarching predicate if applicable.
+        let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } =
+            *poly_trait_ref;
+        let hir::TraitBoundModifiers { constness, polarity } = modifiers;
+
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
+
+        // Relaxed bounds `?Trait` and `PointeeSized` bounds aren't represented in the `middle::ty` IR
+        // as they denote the *absence* of a default bound. However, we can't bail out early here since
+        // we still need to perform several validation steps (see below). Instead, simply "pour" all
+        // resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end.
+        let (polarity, bounds) = match polarity {
+            rustc_ast::BoundPolarity::Positive
+                if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) =>
+            {
+                // To elaborate on the comment directly above, regarding `PointeeSized` specifically,
+                // we don't "reify" such bounds to avoid trait system limitations -- namely,
+                // non-global where-clauses being preferred over item bounds (where `PointeeSized`
+                // bounds would be proven) -- which can result in errors when a `PointeeSized`
+                // supertrait / bound / predicate is added to some items.
+                (ty::PredicatePolarity::Positive, &mut Vec::new())
+            }
+            rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
+            rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
+            rustc_ast::BoundPolarity::Maybe(_) => {
+                (ty::PredicatePolarity::Positive, &mut Vec::new())
+            }
+        };
+
         let trait_segment = trait_ref.path.segments.last().unwrap();
 
         let _ = self.prohibit_generic_args(
@@ -775,7 +803,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(self_ty),
         );
 
-        let tcx = self.tcx();
         let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
         debug!(?bound_vars);
 
@@ -786,27 +813,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         debug!(?poly_trait_ref);
 
-        let polarity = match polarity {
-            rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
-            rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
-            rustc_ast::BoundPolarity::Maybe(_) => {
-                // Validate associated type at least. We may want to reject these
-                // outright in the future...
-                for constraint in trait_segment.args().constraints {
-                    let _ = self.lower_assoc_item_constraint(
-                        trait_ref.hir_ref_id,
-                        poly_trait_ref,
-                        constraint,
-                        &mut Default::default(),
-                        &mut Default::default(),
-                        constraint.span,
-                        predicate_filter,
-                    );
-                }
-                return arg_count;
-            }
-        };
-
         // We deal with const conditions later.
         match predicate_filter {
             PredicateFilter::All
@@ -909,7 +915,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // Don't register any associated item constraints for negative bounds,
             // since we should have emitted an error for them earlier, and they
             // would not be well-formed!
-            if polarity != ty::PredicatePolarity::Positive {
+            if polarity == ty::PredicatePolarity::Negative {
                 self.dcx().span_delayed_bug(
                     constraint.span,
                     "negative trait bounds should not have assoc item constraints",
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index b2a229ad651..6d67535da5f 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1775,7 +1775,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     );
                 }
 
-                let reported = err.emit_unless(unsized_return);
+                let reported = err.emit_unless_delay(unsized_return);
 
                 self.final_ty = Some(Ty::new_error(fcx.tcx, reported));
             }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 067ee0f0eb0..08e8164078c 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1549,7 +1549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // If the assignment expression itself is ill-formed, don't
         // bother emitting another error
-        err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error())
+        err.emit_unless_delay(lhs_ty.references_error() || rhs_ty.references_error())
     }
 
     pub(super) fn check_expr_let(
@@ -3865,7 +3865,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.dcx()
                             .create_err(NoVariantNamed { span: ident.span, ident, ty: container })
                             .with_span_label(field.span, "variant not found")
-                            .emit_unless(container.references_error());
+                            .emit_unless_delay(container.references_error());
                         break;
                     };
                     let Some(&subfield) = fields.next() else {
@@ -3897,7 +3897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 enum_span: field.span,
                                 field_span: subident.span,
                             })
-                            .emit_unless(container.references_error());
+                            .emit_unless_delay(container.references_error());
                         break;
                     };
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index cc33764e485..a69057145f1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -700,6 +700,10 @@ struct LLVMRustSanitizerOptions {
 #ifdef ENZYME
 extern "C" void registerEnzymeAndPassPipeline(llvm::PassBuilder &PB,
                                               /* augmentPassBuilder */ bool);
+
+extern "C" {
+extern llvm::cl::opt<std::string> EnzymeFunctionToAnalyze;
+}
 #endif
 
 extern "C" LLVMRustResult LLVMRustOptimize(
@@ -1069,6 +1073,15 @@ extern "C" LLVMRustResult LLVMRustOptimize(
       return LLVMRustResult::Failure;
     }
 
+    // Check if PrintTAFn was used and add type analysis pass if needed
+    if (!EnzymeFunctionToAnalyze.empty()) {
+      if (auto Err = PB.parsePassPipeline(MPM, "print-type-analysis")) {
+        std::string ErrMsg = toString(std::move(Err));
+        LLVMRustSetLastError(ErrMsg.c_str());
+        return LLVMRustResult::Failure;
+      }
+    }
+
     if (PrintAfterEnzyme) {
       // Handle the Rust flag `-Zautodiff=PrintModAfter`.
       std::string Banner = "Module after EnzymeNewPM";
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index e65c7a68426..438eff33054 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -12,7 +12,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
-use rustc_errors::DiagCtxtHandle;
 use rustc_expand::base::SyntaxExtension;
 use rustc_fs_util::try_canonicalize;
 use rustc_hir as hir;
@@ -23,8 +22,10 @@ use rustc_middle::bug;
 use rustc_middle::ty::data_structures::IndexSet;
 use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
 use rustc_proc_macro::bridge::client::ProcMacro;
+use rustc_session::Session;
 use rustc_session::config::{
-    CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, TargetModifier,
+    CrateType, ExtendedTargetModifierInfo, ExternLocation, Externs, OptionsTargetModifiers,
+    TargetModifier,
 };
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
 use rustc_session::lint::{self, BuiltinLintDiag};
@@ -70,6 +71,8 @@ pub struct CStore {
 
     /// Unused externs of the crate
     unused_externs: Vec<Symbol>,
+
+    used_extern_options: FxHashSet<Symbol>,
 }
 
 impl std::fmt::Debug for CStore {
@@ -78,28 +81,6 @@ impl std::fmt::Debug for CStore {
     }
 }
 
-pub struct CrateLoader<'a, 'tcx: 'a> {
-    // Immutable configuration.
-    tcx: TyCtxt<'tcx>,
-    // Mutable output.
-    cstore: &'a mut CStore,
-    used_extern_options: &'a mut FxHashSet<Symbol>,
-}
-
-impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> {
-    type Target = TyCtxt<'tcx>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.tcx
-    }
-}
-
-impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
-    fn dcx(&self) -> DiagCtxtHandle<'tcx> {
-        self.tcx.dcx()
-    }
-}
-
 pub enum LoadedMacro {
     MacroDef {
         def: MacroDef,
@@ -227,8 +208,8 @@ impl CStore {
 
     fn intern_stable_crate_id<'tcx>(
         &mut self,
-        root: &CrateRoot,
         tcx: TyCtxt<'tcx>,
+        root: &CrateRoot,
     ) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {
         assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());
         let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {
@@ -495,21 +476,18 @@ impl CStore {
             has_global_allocator: false,
             has_alloc_error_handler: false,
             unused_externs: Vec::new(),
+            used_extern_options: Default::default(),
         }
     }
-}
 
-impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        cstore: &'a mut CStore,
-        used_extern_options: &'a mut FxHashSet<Symbol>,
-    ) -> Self {
-        CrateLoader { tcx, cstore, used_extern_options }
-    }
-
-    fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
-        for (cnum, data) in self.cstore.iter_crate_data() {
+    fn existing_match(
+        &self,
+        externs: &Externs,
+        name: Symbol,
+        hash: Option<Svh>,
+        kind: PathKind,
+    ) -> Option<CrateNum> {
+        for (cnum, data) in self.iter_crate_data() {
             if data.name() != name {
                 trace!("{} did not match {}", data.name(), name);
                 continue;
@@ -533,8 +511,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             // We're also sure to compare *paths*, not actual byte slices. The
             // `source` stores paths which are normalized which may be different
             // from the strings on the command line.
-            let source = self.cstore.get_crate_data(cnum).cdata.source();
-            if let Some(entry) = self.sess.opts.externs.get(name.as_str()) {
+            let source = self.get_crate_data(cnum).cdata.source();
+            if let Some(entry) = externs.get(name.as_str()) {
                 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
                 if let Some(mut files) = entry.files() {
                     if files.any(|l| {
@@ -587,6 +565,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     /// command parameter is set to `public-dependency`
     fn is_private_dep(
         &self,
+        externs: &Externs,
         name: Symbol,
         private_dep: Option<bool>,
         origin: CrateOrigin<'_>,
@@ -595,7 +574,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             return true;
         }
 
-        let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
+        let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep);
         match (extern_private, private_dep) {
             // Explicit non-private via `--extern`, explicit non-private from metadata, or
             // unspecified with default to public.
@@ -605,8 +584,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn register_crate(
+    fn register_crate<'tcx>(
         &mut self,
+        tcx: TyCtxt<'tcx>,
         host_lib: Option<Library>,
         origin: CrateOrigin<'_>,
         lib: Library,
@@ -615,15 +595,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         private_dep: Option<bool>,
     ) -> Result<CrateNum, CrateError> {
         let _prof_timer =
-            self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
+            tcx.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
 
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        let private_dep = self.is_private_dep(name, private_dep, origin);
+        let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
 
         // Claim this crate number and cache it
-        let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
+        let feed = self.intern_stable_crate_id(tcx, &crate_root)?;
         let cnum = feed.key();
 
         info!(
@@ -643,8 +623,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             &crate_paths
         };
 
-        let cnum_map =
-            self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
+        let cnum_map = self.resolve_crate_deps(
+            tcx,
+            dep_root,
+            &crate_root,
+            &metadata,
+            cnum,
+            dep_kind,
+            private_dep,
+        )?;
 
         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
@@ -656,14 +643,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
+            Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?)
         } else {
             None
         };
 
         let crate_metadata = CrateMetadata::new(
-            self.sess,
-            self.cstore,
+            tcx.sess,
+            self,
             metadata,
             crate_root,
             raw_proc_macros,
@@ -675,13 +662,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             host_hash,
         );
 
-        self.cstore.set_crate_data(cnum, crate_metadata);
+        self.set_crate_data(cnum, crate_metadata);
 
         Ok(cnum)
     }
 
-    fn load_proc_macro<'b>(
+    fn load_proc_macro<'a, 'b>(
         &self,
+        sess: &'a Session,
         locator: &mut CrateLocator<'b>,
         crate_rejections: &mut CrateRejections,
         path_kind: PathKind,
@@ -690,13 +678,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     where
         'a: 'b,
     {
-        if self.sess.opts.unstable_opts.dual_proc_macros {
+        if sess.opts.unstable_opts.dual_proc_macros {
             // Use a new crate locator and crate rejections so trying to load a proc macro doesn't
             // affect the error message we emit
             let mut proc_macro_locator = locator.clone();
 
             // Try to load a proc macro
-            proc_macro_locator.for_target_proc_macro(self.sess, path_kind);
+            proc_macro_locator.for_target_proc_macro(sess, path_kind);
 
             // Load the proc macro crate for the target
             let target_result =
@@ -713,7 +701,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             *crate_rejections = CrateRejections::default();
 
             // Load the proc macro crate for the host
-            locator.for_proc_macro(self.sess, path_kind);
+            locator.for_proc_macro(sess, path_kind);
 
             locator.hash = host_hash;
 
@@ -734,7 +722,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             let mut proc_macro_locator = locator.clone();
 
             // Load the proc macro crate for the host
-            proc_macro_locator.for_proc_macro(self.sess, path_kind);
+            proc_macro_locator.for_proc_macro(sess, path_kind);
 
             let Some(host_result) =
                 self.load(&mut proc_macro_locator, &mut CrateRejections::default())?
@@ -746,32 +734,39 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn resolve_crate(
+    fn resolve_crate<'tcx>(
         &mut self,
+        tcx: TyCtxt<'tcx>,
         name: Symbol,
         span: Span,
         dep_kind: CrateDepKind,
         origin: CrateOrigin<'_>,
     ) -> Option<CrateNum> {
         self.used_extern_options.insert(name);
-        match self.maybe_resolve_crate(name, dep_kind, origin) {
+        match self.maybe_resolve_crate(tcx, name, dep_kind, origin) {
             Ok(cnum) => {
-                self.cstore.set_used_recursively(cnum);
+                self.set_used_recursively(cnum);
                 Some(cnum)
             }
             Err(err) => {
                 debug!("failed to resolve crate {} {:?}", name, dep_kind);
                 let missing_core = self
-                    .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern)
+                    .maybe_resolve_crate(
+                        tcx,
+                        sym::core,
+                        CrateDepKind::Explicit,
+                        CrateOrigin::Extern,
+                    )
                     .is_err();
-                err.report(self.sess, span, missing_core);
+                err.report(tcx.sess, span, missing_core);
                 None
             }
         }
     }
 
-    fn maybe_resolve_crate<'b>(
+    fn maybe_resolve_crate<'b, 'tcx>(
         &'b mut self,
+        tcx: TyCtxt<'tcx>,
         name: Symbol,
         mut dep_kind: CrateDepKind,
         origin: CrateOrigin<'b>,
@@ -789,17 +784,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
         let private_dep = origin.private_dep();
 
-        let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
+        let result = if let Some(cnum) =
+            self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind)
+        {
             (LoadResult::Previous(cnum), None)
         } else {
             info!("falling back to a load");
             let mut locator = CrateLocator::new(
-                self.sess,
-                &*self.cstore.metadata_loader,
+                tcx.sess,
+                &*self.metadata_loader,
                 name,
                 // The all loop is because `--crate-type=rlib --crate-type=rlib` is
                 // legal and produces both inside this type.
-                self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
+                tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
                 hash,
                 extra_filename,
                 path_kind,
@@ -812,6 +809,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                     info!("falling back to loading proc_macro");
                     dep_kind = CrateDepKind::MacrosOnly;
                     match self.load_proc_macro(
+                        tcx.sess,
                         &mut locator,
                         &mut crate_rejections,
                         path_kind,
@@ -831,8 +829,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 // not specified by `--extern` on command line parameters, it may be
                 // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
                 // `public-dependency` here.
-                let private_dep = self.is_private_dep(name, private_dep, origin);
-                let data = self.cstore.get_crate_data_mut(cnum);
+                let private_dep =
+                    self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
+                let data = self.get_crate_data_mut(cnum);
                 if data.is_proc_macro_crate() {
                     dep_kind = CrateDepKind::MacrosOnly;
                 }
@@ -842,7 +841,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
             (LoadResult::Loaded(library), host_library) => {
                 info!("register newly loaded library for `{}`", name);
-                self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
+                self.register_crate(tcx, host_library, origin, library, dep_kind, name, private_dep)
             }
             _ => panic!(),
         }
@@ -863,7 +862,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // duplicates by just using the first crate.
         let root = library.metadata.get_root();
         let mut result = LoadResult::Loaded(library);
-        for (cnum, data) in self.cstore.iter_crate_data() {
+        for (cnum, data) in self.iter_crate_data() {
             if data.name() == root.name() && root.hash() == data.hash() {
                 assert!(locator.hash.is_none());
                 info!("load success, going to previous cnum: {}", cnum);
@@ -877,6 +876,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     /// Go through the crate metadata and load any crates that it references.
     fn resolve_crate_deps(
         &mut self,
+        tcx: TyCtxt<'_>,
         dep_root: &CratePaths,
         crate_root: &CrateRoot,
         metadata: &MetadataBlob,
@@ -913,6 +913,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 _ => dep.kind,
             };
             let cnum = self.maybe_resolve_crate(
+                tcx,
                 dep.name,
                 dep_kind,
                 CrateOrigin::IndirectDependency {
@@ -930,10 +931,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
     fn dlsym_proc_macros(
         &self,
+        sess: &Session,
         path: &Path,
         stable_crate_id: StableCrateId,
     ) -> Result<&'static [ProcMacro], CrateError> {
-        let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+        let sym_name = sess.generate_proc_macro_decls_symbol(stable_crate_id);
         debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
 
         unsafe {
@@ -955,10 +957,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
+    fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         // If we're only compiling an rlib, then there's no need to select a
         // panic runtime, so we just skip this section entirely.
-        let only_rlib = self.tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
+        let only_rlib = tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
         if only_rlib {
             info!("panic runtime injection skipped, only generating rlib");
             return;
@@ -968,7 +970,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // the same time we perform some general validation of the DAG we've got
         // going such as ensuring everything has a compatible panic strategy.
         let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
-        for (_cnum, data) in self.cstore.iter_crate_data() {
+        for (_cnum, data) in self.iter_crate_data() {
             needs_panic_runtime |= data.needs_panic_runtime();
         }
 
@@ -987,7 +989,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Also note that we have yet to perform validation of the crate graph
         // in terms of everyone has a compatible panic runtime format, that's
         // performed later as part of the `dependency_format` module.
-        let desired_strategy = self.sess.panic_strategy();
+        let desired_strategy = tcx.sess.panic_strategy();
         let name = match desired_strategy {
             PanicStrategy::Unwind => sym::panic_unwind,
             PanicStrategy::Abort => sym::panic_abort,
@@ -995,64 +997,64 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         info!("panic runtime not found -- loading {}", name);
 
         let Some(cnum) =
-            self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
+            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
         else {
             return;
         };
-        let data = self.cstore.get_crate_data(cnum);
+        let data = self.get_crate_data(cnum);
 
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
         if !data.is_panic_runtime() {
-            self.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
+            tcx.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
         }
         if data.required_panic_strategy() != Some(desired_strategy) {
-            self.dcx()
+            tcx.dcx()
                 .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
         }
 
-        self.cstore.injected_panic_runtime = Some(cnum);
+        self.injected_panic_runtime = Some(cnum);
     }
 
-    fn inject_profiler_runtime(&mut self) {
+    fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {
         let needs_profiler_runtime =
-            self.sess.instrument_coverage() || self.sess.opts.cg.profile_generate.enabled();
-        if !needs_profiler_runtime || self.sess.opts.unstable_opts.no_profiler_runtime {
+            tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled();
+        if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime {
             return;
         }
 
         info!("loading profiler");
 
-        let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
+        let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime);
         let Some(cnum) =
-            self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
+            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
         else {
             return;
         };
-        let data = self.cstore.get_crate_data(cnum);
+        let data = self.get_crate_data(cnum);
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
         if !data.is_profiler_runtime() {
-            self.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
+            tcx.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
         }
     }
 
-    fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
-        self.cstore.has_global_allocator =
+    fn inject_allocator_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
+        self.has_global_allocator =
             match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) {
                 [span1, span2, ..] => {
-                    self.dcx()
+                    tcx.dcx()
                         .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                     true
                 }
                 spans => !spans.is_empty(),
             };
-        self.cstore.has_alloc_error_handler = match &*fn_spans(
+        self.has_alloc_error_handler = match &*fn_spans(
             krate,
             Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
         ) {
             [span1, span2, ..] => {
-                self.dcx()
+                tcx.dcx()
                     .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
                 true
             }
@@ -1063,7 +1065,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // about through the `#![needs_allocator]` attribute and is typically
         // written down in liballoc.
         if !attr::contains_name(&krate.attrs, sym::needs_allocator)
-            && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
+            && !self.iter_crate_data().any(|(_, data)| data.needs_allocator())
         {
             return;
         }
@@ -1071,7 +1073,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // At this point we've determined that we need an allocator. Let's see
         // if our compilation session actually needs an allocator based on what
         // we're emitting.
-        let all_rlib = self.tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
+        let all_rlib = tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
         if all_rlib {
             return;
         }
@@ -1086,12 +1088,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         #[allow(rustc::symbol_intern_string_literal)]
         let this_crate = Symbol::intern("this crate");
 
-        let mut global_allocator = self.cstore.has_global_allocator.then_some(this_crate);
-        for (_, data) in self.cstore.iter_crate_data() {
+        let mut global_allocator = self.has_global_allocator.then_some(this_crate);
+        for (_, data) in self.iter_crate_data() {
             if data.has_global_allocator() {
                 match global_allocator {
                     Some(other_crate) => {
-                        self.dcx().emit_err(errors::ConflictingGlobalAlloc {
+                        tcx.dcx().emit_err(errors::ConflictingGlobalAlloc {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -1100,12 +1102,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 }
             }
         }
-        let mut alloc_error_handler = self.cstore.has_alloc_error_handler.then_some(this_crate);
-        for (_, data) in self.cstore.iter_crate_data() {
+        let mut alloc_error_handler = self.has_alloc_error_handler.then_some(this_crate);
+        for (_, data) in self.iter_crate_data() {
             if data.has_alloc_error_handler() {
                 match alloc_error_handler {
                     Some(other_crate) => {
-                        self.dcx().emit_err(errors::ConflictingAllocErrorHandler {
+                        tcx.dcx().emit_err(errors::ConflictingAllocErrorHandler {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -1116,35 +1118,36 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
 
         if global_allocator.is_some() {
-            self.cstore.allocator_kind = Some(AllocatorKind::Global);
+            self.allocator_kind = Some(AllocatorKind::Global);
         } else {
             // Ok we haven't found a global allocator but we still need an
             // allocator. At this point our allocator request is typically fulfilled
             // by the standard library, denoted by the `#![default_lib_allocator]`
             // attribute.
             if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
-                && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
+                && !self.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
             {
-                self.dcx().emit_err(errors::GlobalAllocRequired);
+                tcx.dcx().emit_err(errors::GlobalAllocRequired);
             }
-            self.cstore.allocator_kind = Some(AllocatorKind::Default);
+            self.allocator_kind = Some(AllocatorKind::Default);
         }
 
         if alloc_error_handler.is_some() {
-            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
+            self.alloc_error_handler_kind = Some(AllocatorKind::Global);
         } else {
             // The alloc crate provides a default allocation error handler if
             // one isn't specified.
-            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
+            self.alloc_error_handler_kind = Some(AllocatorKind::Default);
         }
     }
 
-    fn inject_forced_externs(&mut self) {
-        for (name, entry) in self.sess.opts.externs.iter() {
+    fn inject_forced_externs(&mut self, tcx: TyCtxt<'_>) {
+        for (name, entry) in tcx.sess.opts.externs.iter() {
             if entry.force {
                 let name_interned = Symbol::intern(name);
                 if !self.used_extern_options.contains(&name_interned) {
                     self.resolve_crate(
+                        tcx,
                         name_interned,
                         DUMMY_SP,
                         CrateDepKind::Explicit,
@@ -1156,7 +1159,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     /// Inject the `compiler_builtins` crate if it is not already in the graph.
-    fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
+    fn inject_compiler_builtins(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
         if attr::contains_name(&krate.attrs, sym::compiler_builtins)
             || attr::contains_name(&krate.attrs, sym::no_core)
@@ -1167,7 +1170,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
         // the common case since usually it appears as a dependency of `std` or `alloc`.
-        for (cnum, cmeta) in self.cstore.iter_crate_data() {
+        for (cnum, cmeta) in self.iter_crate_data() {
             if cmeta.is_compiler_builtins() {
                 info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
                 return;
@@ -1176,6 +1179,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.
         let Some(cnum) = self.resolve_crate(
+            tcx,
             sym::compiler_builtins,
             krate.spans.inner_span.shrink_to_lo(),
             CrateDepKind::Explicit,
@@ -1186,17 +1190,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         };
 
         // Sanity check that the loaded crate is `#![compiler_builtins]`
-        let cmeta = self.cstore.get_crate_data(cnum);
+        let cmeta = self.get_crate_data(cnum);
         if !cmeta.is_compiler_builtins() {
-            self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
+            tcx.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
         }
     }
 
-    fn report_unused_deps(&mut self, krate: &ast::Crate) {
+    fn report_unused_deps_in_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         // Make a point span rather than covering the whole file
         let span = krate.spans.inner_span.shrink_to_lo();
         // Complain about anything left over
-        for (name, entry) in self.sess.opts.externs.iter() {
+        for (name, entry) in tcx.sess.opts.externs.iter() {
             if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
                 // Don't worry about pathless `--extern foo` sysroot references
                 continue;
@@ -1211,25 +1215,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
 
             // Got a real unused --extern
-            if self.sess.opts.json_unused_externs.is_enabled() {
-                self.cstore.unused_externs.push(name_interned);
+            if tcx.sess.opts.json_unused_externs.is_enabled() {
+                self.unused_externs.push(name_interned);
                 continue;
             }
 
-            self.sess.psess.buffer_lint(
+            tcx.sess.psess.buffer_lint(
                 lint::builtin::UNUSED_CRATE_DEPENDENCIES,
                 span,
                 ast::CRATE_NODE_ID,
                 BuiltinLintDiag::UnusedCrateDependency {
                     extern_crate: name_interned,
-                    local_crate: self.tcx.crate_name(LOCAL_CRATE),
+                    local_crate: tcx.crate_name(LOCAL_CRATE),
                 },
             );
         }
     }
 
-    fn report_future_incompatible_deps(&self, krate: &ast::Crate) {
-        let name = self.tcx.crate_name(LOCAL_CRATE);
+    fn report_future_incompatible_deps(&self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
+        let name = tcx.crate_name(LOCAL_CRATE);
 
         if name.as_str() == "wasm_bindgen" {
             let major = env::var("CARGO_PKG_VERSION_MAJOR")
@@ -1257,26 +1261,27 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             // Make a point span rather than covering the whole file
             let span = krate.spans.inner_span.shrink_to_lo();
 
-            self.sess.dcx().emit_err(errors::WasmCAbi { span });
+            tcx.sess.dcx().emit_err(errors::WasmCAbi { span });
         }
     }
 
-    pub fn postprocess(&mut self, krate: &ast::Crate) {
-        self.inject_compiler_builtins(krate);
-        self.inject_forced_externs();
-        self.inject_profiler_runtime();
-        self.inject_allocator_crate(krate);
-        self.inject_panic_runtime(krate);
+    pub fn postprocess(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
+        self.inject_compiler_builtins(tcx, krate);
+        self.inject_forced_externs(tcx);
+        self.inject_profiler_runtime(tcx);
+        self.inject_allocator_crate(tcx, krate);
+        self.inject_panic_runtime(tcx, krate);
 
-        self.report_unused_deps(krate);
-        self.report_future_incompatible_deps(krate);
+        self.report_unused_deps_in_crate(tcx, krate);
+        self.report_future_incompatible_deps(tcx, krate);
 
-        info!("{:?}", CrateDump(self.cstore));
+        info!("{:?}", CrateDump(self));
     }
 
     /// Process an `extern crate foo` AST node.
     pub fn process_extern_crate(
         &mut self,
+        tcx: TyCtxt<'_>,
         item: &ast::Item,
         def_id: LocalDefId,
         definitions: &Definitions,
@@ -1286,7 +1291,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name);
                 let name = match orig_name {
                     Some(orig_name) => {
-                        validate_crate_name(self.sess, orig_name, Some(item.span));
+                        validate_crate_name(tcx.sess, orig_name, Some(item.span));
                         orig_name
                     }
                     None => ident.name,
@@ -1297,10 +1302,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                     CrateDepKind::Explicit
                 };
 
-                let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?;
+                let cnum =
+                    self.resolve_crate(tcx, name, item.span, dep_kind, CrateOrigin::Extern)?;
 
                 let path_len = definitions.def_path(def_id).data.len();
-                self.cstore.update_extern_crate(
+                self.update_extern_crate(
                     cnum,
                     ExternCrate {
                         src: ExternCrateSource::Extern(def_id.to_def_id()),
@@ -1315,10 +1321,16 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
-        let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
+    pub fn process_path_extern(
+        &mut self,
+        tcx: TyCtxt<'_>,
+        name: Symbol,
+        span: Span,
+    ) -> Option<CrateNum> {
+        let cnum =
+            self.resolve_crate(tcx, name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
 
-        self.cstore.update_extern_crate(
+        self.update_extern_crate(
             cnum,
             ExternCrate {
                 src: ExternCrateSource::Path,
@@ -1332,8 +1344,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         Some(cnum)
     }
 
-    pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
-        self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
+    pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option<CrateNum> {
+        self.maybe_resolve_crate(tcx, name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 133111ff15d..27ead514531 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -702,8 +702,11 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         read_provenance: bool,
     ) -> AllocResult<Scalar<Prov>> {
         // First and foremost, if anything is uninit, bail.
-        if self.init_mask.is_range_initialized(range).is_err() {
-            return Err(AllocError::InvalidUninitBytes(None));
+        if let Err(bad) = self.init_mask.is_range_initialized(range) {
+            return Err(AllocError::InvalidUninitBytes(Some(BadBytesAccess {
+                access: range,
+                bad,
+            })));
         }
 
         // Get the integer part of the result. We HAVE TO check provenance before returning this!
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 07717b7c069..6657f89ceb5 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -579,7 +579,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => {
                     let src = self.evaluated[value].as_ref()?;
                     let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
-                    self.ecx.unsize_into(src, ty, &dest.clone().into()).discard_err()?;
+                    self.ecx.unsize_into(src, ty, &dest).discard_err()?;
                     self.ecx
                         .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
                         .discard_err()?;
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 93a81f0dca5..7f9234d1dc8 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -64,15 +64,15 @@ fn process<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
     caller: ty::Instance<'tcx>,
     target: LocalDefId,
-    seen: &mut FxHashSet<ty::Instance<'tcx>>,
+    seen: &mut FxHashMap<ty::Instance<'tcx>, bool>,
     involved: &mut FxHashSet<LocalDefId>,
     recursion_limiter: &mut FxHashMap<DefId, usize>,
     recursion_limit: Limit,
 ) -> bool {
     trace!(%caller);
-    let mut cycle_found = false;
+    let mut reaches_root = false;
 
-    for &(callee, args) in tcx.mir_inliner_callees(caller.def) {
+    for &(callee_def_id, args) in tcx.mir_inliner_callees(caller.def) {
         let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions(
             tcx,
             typing_env,
@@ -81,14 +81,17 @@ fn process<'tcx>(
             trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping");
             continue;
         };
-        let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else {
-            trace!(?callee, "cannot resolve, skipping");
+        let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee_def_id, args)
+        else {
+            trace!(?callee_def_id, "cannot resolve, skipping");
             continue;
         };
 
         // Found a path.
         if callee.def_id() == target.to_def_id() {
-            cycle_found = true;
+            reaches_root = true;
+            seen.insert(callee, true);
+            continue;
         }
 
         if tcx.is_constructor(callee.def_id()) {
@@ -101,10 +104,17 @@ fn process<'tcx>(
             continue;
         }
 
-        if seen.insert(callee) {
+        let callee_reaches_root = if let Some(&c) = seen.get(&callee) {
+            // Even if we have seen this callee before, and thus don't need
+            // to recurse into it, we still need to propagate whether it reaches
+            // the root so that we can mark all the involved callers, in case we
+            // end up reaching that same recursive callee through some *other* cycle.
+            c
+        } else {
+            seen.insert(callee, false);
             let recursion = recursion_limiter.entry(callee.def_id()).or_default();
             trace!(?callee, recursion = *recursion);
-            let found_recursion = if recursion_limit.value_within_limit(*recursion) {
+            let callee_reaches_root = if recursion_limit.value_within_limit(*recursion) {
                 *recursion += 1;
                 ensure_sufficient_stack(|| {
                     process(
@@ -122,17 +132,19 @@ fn process<'tcx>(
                 // Pessimistically assume that there could be recursion.
                 true
             };
-            if found_recursion {
-                if let Some(callee) = callee.def_id().as_local() {
-                    // Calling `optimized_mir` of a non-local definition cannot cycle.
-                    involved.insert(callee);
-                }
-                cycle_found = true;
+            seen.insert(callee, callee_reaches_root);
+            callee_reaches_root
+        };
+        if callee_reaches_root {
+            if let Some(callee_def_id) = callee.def_id().as_local() {
+                // Calling `optimized_mir` of a non-local definition cannot cycle.
+                involved.insert(callee_def_id);
             }
+            reaches_root = true;
         }
     }
 
-    cycle_found
+    reaches_root
 }
 
 #[instrument(level = "debug", skip(tcx), ret)]
@@ -166,7 +178,7 @@ pub(crate) fn mir_callgraph_cyclic<'tcx>(
         typing_env,
         root_instance,
         root,
-        &mut FxHashSet::default(),
+        &mut FxHashMap::default(),
         &mut involved,
         &mut FxHashMap::default(),
         recursion_limit,
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 098dc9dbaf0..650b85d99d2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1219,10 +1219,8 @@ where
             // the type (even if after unification and processing nested goals
             // it does not hold) will disqualify the built-in auto impl.
             //
-            // This differs from the current stable behavior and fixes #84857.
-            // Due to breakage found via crater, we currently instead lint
-            // patterns which can be used to exploit this unsoundness on stable,
-            // see #93367 for more details.
+            // We've originally had a more permissive check here which resulted
+            // in unsoundness, see #84857.
             ty::Bool
             | ty::Char
             | ty::Int(_)
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index 0b97d4e6993..6de001fc998 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -34,9 +34,12 @@ pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Sp
 
 // When we get a `)` or `]` for `{`, we should emit help message here
 // it's more friendly compared to report `unmatched error` in later phase
-fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool {
+pub(super) fn report_missing_open_delim(
+    err: &mut Diag<'_>,
+    unmatched_delims: &mut Vec<UnmatchedDelim>,
+) -> bool {
     let mut reported_missing_open = false;
-    for unmatch_brace in unmatched_delims.iter() {
+    unmatched_delims.retain(|unmatch_brace| {
         if let Some(delim) = unmatch_brace.found_delim
             && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket)
         {
@@ -45,13 +48,20 @@ fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDe
                 Delimiter::Bracket => "[",
                 _ => unreachable!(),
             };
+
+            if let Some(unclosed_span) = unmatch_brace.unclosed_span {
+                err.span_label(unclosed_span, "the nearest open delimiter");
+            }
             err.span_label(
                 unmatch_brace.found_span.shrink_to_lo(),
                 format!("missing open `{missed_open}` for this delimiter"),
             );
             reported_missing_open = true;
+            false
+        } else {
+            true
         }
-    }
+    });
     reported_missing_open
 }
 
@@ -61,10 +71,6 @@ pub(super) fn report_suspicious_mismatch_block(
     sm: &SourceMap,
     delim: Delimiter,
 ) {
-    if report_missing_open_delim(err, &diag_info.unmatched_delims) {
-        return;
-    }
-
     let mut matched_spans: Vec<(Span, bool)> = diag_info
         .matching_block_spans
         .iter()
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index fbea958dcc5..64748199f28 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -3,7 +3,9 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke
 use rustc_ast_pretty::pprust::token_to_string;
 use rustc_errors::Diag;
 
-use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level};
+use super::diagnostics::{
+    report_missing_open_delim, report_suspicious_mismatch_block, same_indentation_level,
+};
 use super::{Lexer, UnmatchedDelim};
 
 impl<'psess, 'src> Lexer<'psess, 'src> {
@@ -244,7 +246,16 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
         let msg = format!("unexpected closing delimiter: `{token_str}`");
         let mut err = self.dcx().struct_span_err(self.token.span, msg);
 
-        report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim);
+        // if there is no missing open delim, report suspicious mismatch block
+        if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) {
+            report_suspicious_mismatch_block(
+                &mut err,
+                &self.diag_info,
+                self.psess.source_map(),
+                delim,
+            );
+        }
+
         err.span_label(self.token.span, "unexpected closing delimiter");
         err
     }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 675ea9d1e98..737577baa7a 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -49,7 +49,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         ns: Namespace,
         binding: NameBinding<'ra>,
     ) {
-        if let Err(old_binding) = self.try_define(parent, ident, ns, binding, false) {
+        let key = self.new_disambiguated_key(ident, ns);
+        if let Err(old_binding) = self.try_define(parent, key, binding, false) {
             self.report_conflict(parent, ident, ns, old_binding, binding);
         }
     }
@@ -441,18 +442,16 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
 
         self.r.indeterminate_imports.push(import);
         match import.kind {
+            // Don't add unresolved underscore imports to modules
+            ImportKind::Single { target: Ident { name: kw::Underscore, .. }, .. } => {}
             ImportKind::Single { target, type_ns_only, .. } => {
-                // Don't add underscore imports to `single_imports`
-                // because they cannot define any usable names.
-                if target.name != kw::Underscore {
-                    self.r.per_ns(|this, ns| {
-                        if !type_ns_only || ns == TypeNS {
-                            let key = BindingKey::new(target, ns);
-                            let mut resolution = this.resolution(current_module, key).borrow_mut();
-                            resolution.single_imports.insert(import);
-                        }
-                    });
-                }
+                self.r.per_ns(|this, ns| {
+                    if !type_ns_only || ns == TypeNS {
+                        let key = BindingKey::new(target, ns);
+                        let mut resolution = this.resolution(current_module, key).borrow_mut();
+                        resolution.single_imports.insert(import);
+                    }
+                });
             }
             // We don't add prelude imports to the globs since they only affect lexical scopes,
             // which are not relevant to import resolution.
@@ -898,9 +897,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             Some(self.r.graph_root)
         } else {
             let tcx = self.r.tcx;
-            let crate_id = self.r.crate_loader(|c| {
-                c.process_extern_crate(item, local_def_id, &tcx.definitions_untracked())
-            });
+            let crate_id = self.r.cstore_mut().process_extern_crate(
+                self.r.tcx,
+                item,
+                local_def_id,
+                &tcx.definitions_untracked(),
+            );
             crate_id.map(|crate_id| {
                 self.r.extern_crate_map.insert(local_def_id, crate_id);
                 self.r.expect_module(crate_id.as_def_id())
@@ -1406,12 +1408,9 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             let parent = self.parent_scope.module;
             let expansion = self.parent_scope.expansion;
             self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion);
-        } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob)
-            && ident.name != kw::Underscore
-        {
-            // Don't add underscore names, they cannot be looked up anyway.
+        } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) {
             let impl_def_id = self.r.tcx.local_parent(local_def_id);
-            let key = BindingKey::new(ident, ns);
+            let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns);
             self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key);
         }
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f6f45adabe9..d72fbc189e7 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1425,7 +1425,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
+                let Some(crate_id) =
+                    self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
                 else {
                     continue;
                 };
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index b4c15ed1ca7..0a4c25b0eb0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -25,7 +25,7 @@ use rustc_span::{Ident, Span, Symbol, kw, sym};
 use smallvec::SmallVec;
 use tracing::debug;
 
-use crate::Namespace::{self, *};
+use crate::Namespace::*;
 use crate::diagnostics::{DiagMode, Suggestion, import_candidates};
 use crate::errors::{
     CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
@@ -338,20 +338,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     pub(crate) fn try_define(
         &mut self,
         module: Module<'ra>,
-        ident: Ident,
-        ns: Namespace,
+        key: BindingKey,
         binding: NameBinding<'ra>,
         warn_ambiguity: bool,
     ) -> Result<(), NameBinding<'ra>> {
         let res = binding.res();
-        self.check_reserved_macro_name(ident, res);
+        self.check_reserved_macro_name(key.ident, res);
         self.set_binding_parent_module(binding, module);
-        // Even if underscore names cannot be looked up, we still need to add them to modules,
-        // because they can be fetched by glob imports from those modules, and bring traits
-        // into scope both directly and through glob imports.
-        let key = BindingKey::new_disambiguated(ident, ns, || {
-            (module.0.0.lazy_resolutions.borrow().len() + 1).try_into().unwrap()
-        });
         self.update_resolution(module, key, warn_ambiguity, |this, resolution| {
             if let Some(old_binding) = resolution.best_binding() {
                 if res == Res::Err && old_binding.res() != Res::Err {
@@ -390,7 +383,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     (old_glob @ true, false) | (old_glob @ false, true) => {
                         let (glob_binding, non_glob_binding) =
                             if old_glob { (old_binding, binding) } else { (binding, old_binding) };
-                        if ns == MacroNS
+                        if key.ns == MacroNS
                             && non_glob_binding.expansion != LocalExpnId::ROOT
                             && glob_binding.res() != non_glob_binding.res()
                         {
@@ -496,10 +489,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             };
             if self.is_accessible_from(binding.vis, scope) {
                 let imported_binding = self.import(binding, *import);
+                let key = BindingKey { ident, ..key };
                 let _ = self.try_define(
                     import.parent_scope.module,
-                    ident,
-                    key.ns,
+                    key,
                     imported_binding,
                     warn_ambiguity,
                 );
@@ -521,15 +514,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             let dummy_binding = self.dummy_binding;
             let dummy_binding = self.import(dummy_binding, import);
             self.per_ns(|this, ns| {
-                let module = import.parent_scope.module;
-                let _ = this.try_define(module, target, ns, dummy_binding, false);
-                // Don't remove underscores from `single_imports`, they were never added.
-                if target.name != kw::Underscore {
-                    let key = BindingKey::new(target, ns);
-                    this.update_resolution(module, key, false, |_, resolution| {
-                        resolution.single_imports.swap_remove(&import);
-                    })
-                }
+                let key = BindingKey::new(target, ns);
+                let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false);
+                this.update_resolution(import.parent_scope.module, key, false, |_, resolution| {
+                    resolution.single_imports.swap_remove(&import);
+                })
             });
             self.record_use(target, dummy_binding, Used::Other);
         } else if import.imported_module.get().is_none() {
@@ -906,7 +895,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         PendingBinding::Ready(Some(imported_binding))
                     }
                     Err(Determinacy::Determined) => {
-                        // Don't remove underscores from `single_imports`, they were never added.
+                        // Don't update the resolution for underscores, because it was never added.
                         if target.name != kw::Underscore {
                             let key = BindingKey::new(target, ns);
                             this.update_resolution(parent, key, false, |_, resolution| {
@@ -1521,8 +1510,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     .is_some_and(|binding| binding.warn_ambiguity_recursive());
                 let _ = self.try_define(
                     import.parent_scope.module,
-                    key.ident,
-                    key.ns,
+                    key,
                     imported_binding,
                     warn_ambiguity,
                 );
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 93cec8daa5a..a3a770502de 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2913,7 +2913,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                     self.r
                         .dcx()
                         .create_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span })
-                        .emit_unless(is_raw_underscore_lifetime);
+                        .emit_unless_delay(is_raw_underscore_lifetime);
                     // Record lifetime res, so lowering knows there is something fishy.
                     self.record_lifetime_param(param.id, LifetimeRes::Error);
                     continue;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index ee462d90764..69095942f52 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2485,7 +2485,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                             let extern_prelude = self.r.extern_prelude.clone();
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
                                 self.r
-                                    .crate_loader(|c| c.maybe_process_path_extern(ident.name))
+                                    .cstore_mut()
+                                    .maybe_process_path_extern(self.r.tcx, ident.name)
                                     .and_then(|crate_id| {
                                         let crate_mod =
                                             Res::Def(DefKind::Mod, crate_id.as_def_id());
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f38fee8dea5..0d41a822e8a 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -45,7 +45,7 @@ use rustc_attr_data_structures::StrippedCfgItem;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::FreezeReadGuard;
+use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
 use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
@@ -58,7 +58,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId,
 use rustc_hir::definitions::DisambiguatorState;
 use rustc_hir::{PrimTy, TraitCandidate};
 use rustc_index::bit_set::DenseBitSet;
-use rustc_metadata::creader::{CStore, CrateLoader};
+use rustc_metadata::creader::CStore;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::query::Providers;
@@ -532,26 +532,15 @@ struct BindingKey {
     /// identifier.
     ident: Ident,
     ns: Namespace,
-    /// When we add an underscore binding (with ident `_`) to some module, this field has
-    /// a non-zero value that uniquely identifies this binding in that module.
-    /// For non-underscore bindings this field is zero.
-    /// When a key is constructed for name lookup (as opposed to name definition), this field is
-    /// also zero, even for underscore names, so for underscores the lookup will never succeed.
+    /// 0 if ident is not `_`, otherwise a value that's unique to the specific
+    /// `_` in the expanded AST that introduced this binding.
     disambiguator: u32,
 }
 
 impl BindingKey {
     fn new(ident: Ident, ns: Namespace) -> Self {
-        BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 }
-    }
-
-    fn new_disambiguated(
-        ident: Ident,
-        ns: Namespace,
-        disambiguator: impl FnOnce() -> u32,
-    ) -> BindingKey {
-        let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 };
-        BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator }
+        let ident = ident.normalize_to_macros_2_0();
+        BindingKey { ident, ns, disambiguator: 0 }
     }
 }
 
@@ -1098,6 +1087,8 @@ pub struct Resolver<'ra, 'tcx> {
     extern_module_map: RefCell<FxIndexMap<DefId, Module<'ra>>>,
     binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>,
 
+    underscore_disambiguator: u32,
+
     /// Maps glob imports to the names of items actually imported.
     glob_map: FxIndexMap<LocalDefId, FxIndexSet<Symbol>>,
     glob_error: Option<ErrorGuaranteed>,
@@ -1119,7 +1110,6 @@ pub struct Resolver<'ra, 'tcx> {
     builtin_types_bindings: FxHashMap<Symbol, NameBinding<'ra>>,
     builtin_attrs_bindings: FxHashMap<Symbol, NameBinding<'ra>>,
     registered_tool_bindings: FxHashMap<Ident, NameBinding<'ra>>,
-    used_extern_options: FxHashSet<Symbol>,
     macro_names: FxHashSet<Ident>,
     builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind>,
     registered_tools: &'tcx RegisteredTools,
@@ -1510,6 +1500,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             extern_crate_map: Default::default(),
             module_children: Default::default(),
             trait_map: NodeMap::default(),
+            underscore_disambiguator: 0,
             empty_module,
             local_module_map,
             extern_module_map: Default::default(),
@@ -1554,7 +1545,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     (*ident, binding)
                 })
                 .collect(),
-            used_extern_options: Default::default(),
             macro_names: FxHashSet::default(),
             builtin_macros: Default::default(),
             registered_tools,
@@ -1741,18 +1731,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         StableHashingContext::new(self.tcx.sess, self.tcx.untracked())
     }
 
-    fn crate_loader<T>(&mut self, f: impl FnOnce(&mut CrateLoader<'_, '_>) -> T) -> T {
-        f(&mut CrateLoader::new(
-            self.tcx,
-            &mut CStore::from_tcx_mut(self.tcx),
-            &mut self.used_extern_options,
-        ))
-    }
-
     fn cstore(&self) -> FreezeReadGuard<'_, CStore> {
         CStore::from_tcx(self.tcx)
     }
 
+    fn cstore_mut(&self) -> FreezeWriteGuard<'_, CStore> {
+        CStore::from_tcx_mut(self.tcx)
+    }
+
     fn dummy_ext(&self, macro_kind: MacroKind) -> Arc<SyntaxExtension> {
         match macro_kind {
             MacroKind::Bang => Arc::clone(&self.dummy_ext_bang),
@@ -1798,7 +1784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             self.tcx.sess.time("resolve_report_errors", || self.report_errors(krate));
             self.tcx
                 .sess
-                .time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate)));
+                .time("resolve_postprocess", || self.cstore_mut().postprocess(self.tcx, krate));
         });
 
         // Make sure we don't mutate the cstore from here on.
@@ -1895,6 +1881,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         import_ids
     }
 
+    fn new_disambiguated_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
+        let ident = ident.normalize_to_macros_2_0();
+        let disambiguator = if ident.name == kw::Underscore {
+            self.underscore_disambiguator += 1;
+            self.underscore_disambiguator
+        } else {
+            0
+        };
+        BindingKey { ident, ns, disambiguator }
+    }
+
     fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
         if module.populate_on_access.get() {
             module.populate_on_access.set(false);
@@ -2153,7 +2150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             Some(if let Some(binding) = entry.binding {
                 if finalize {
                     if !entry.is_import() {
-                        self.crate_loader(|c| c.process_path_extern(ident.name, ident.span));
+                        self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
                     } else if entry.introduced_by_item {
                         self.record_use(ident, binding, Used::Other);
                     }
@@ -2162,13 +2159,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             } else {
                 let crate_id = if finalize {
                     let Some(crate_id) =
-                        self.crate_loader(|c| c.process_path_extern(ident.name, ident.span))
+                        self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
                     else {
                         return Some(self.dummy_binding);
                     };
                     crate_id
                 } else {
-                    self.crate_loader(|c| c.maybe_process_path_extern(ident.name))?
+                    self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)?
                 };
                 let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
                 self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT)
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 0e8904a7dea..77ef7f56c09 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -530,7 +530,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
         target_trait.for_each_child(self, |this, ident, ns, _binding| {
             // FIXME: Adjust hygiene for idents from globs, like for glob imports.
             if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id)
-                && overriding_keys.contains(&BindingKey::new(ident, ns))
+                && overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns))
             {
                 // The name is overridden, do not produce it from the glob delegation.
             } else {
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 8090c98e7ed..c5e199c3082 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -18,7 +18,6 @@ pub struct Zip<A, B> {
     // index, len and a_len are only used by the specialized version of zip
     index: usize,
     len: usize,
-    a_len: usize,
 }
 impl<A: Iterator, B: Iterator> Zip<A, B> {
     pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
@@ -158,7 +157,6 @@ macro_rules! zip_impl_general_defaults {
                 b,
                 index: 0, // unused
                 len: 0,   // unused
-                a_len: 0, // unused
             }
         }
 
@@ -299,9 +297,8 @@ where
     B: TrustedRandomAccess + Iterator,
 {
     fn new(a: A, b: B) -> Self {
-        let a_len = a.size();
-        let len = cmp::min(a_len, b.size());
-        Zip { a, b, index: 0, len, a_len }
+        let len = cmp::min(a.size(), b.size());
+        Zip { a, b, index: 0, len }
     }
 
     #[inline]
@@ -315,17 +312,6 @@ where
             unsafe {
                 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
             }
-        } else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len {
-            let i = self.index;
-            // as above, increment before executing code that may panic
-            self.index += 1;
-            self.len += 1;
-            // match the base implementation's potential side effects
-            // SAFETY: we just checked that `i` < `self.a.len()`
-            unsafe {
-                self.a.__iterator_get_unchecked(i);
-            }
-            None
         } else {
             None
         }
@@ -371,36 +357,42 @@ where
         A: DoubleEndedIterator + ExactSizeIterator,
         B: DoubleEndedIterator + ExactSizeIterator,
     {
-        if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
-            let sz_a = self.a.size();
-            let sz_b = self.b.size();
-            // Adjust a, b to equal length, make sure that only the first call
-            // of `next_back` does this, otherwise we will break the restriction
-            // on calls to `self.next_back()` after calling `get_unchecked()`.
-            if sz_a != sz_b {
+        // No effects when the iterator is exhausted, to reduce the number of
+        // cases the unsafe code has to handle.
+        // See #137255 for a case where where too many epicycles lead to unsoundness.
+        if self.index < self.len {
+            let old_len = self.len;
+
+            // since get_unchecked and the side-effecting code can execute user code
+            // which can panic we decrement the counter beforehand
+            // so that the same index won't be accessed twice, as required by TrustedRandomAccess.
+            // Additionally this will ensure that the side-effects code won't run a second time.
+            self.len -= 1;
+
+            // Adjust a, b to equal length if we're iterating backwards.
+            if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
+                // note if some forward-iteration already happened then these aren't the real
+                // remaining lengths of the inner iterators, so we have to relate them to
+                // Zip's internal length-tracking.
                 let sz_a = self.a.size();
-                if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
-                    for _ in 0..sz_a - self.len {
-                        // since next_back() may panic we increment the counters beforehand
-                        // to keep Zip's state in sync with the underlying iterator source
-                        self.a_len -= 1;
-                        self.a.next_back();
-                    }
-                    debug_assert_eq!(self.a_len, self.len);
-                }
                 let sz_b = self.b.size();
-                if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {
-                    for _ in 0..sz_b - self.len {
-                        self.b.next_back();
+                // This condition can and must only be true on the first `next_back` call,
+                // otherwise we will break the restriction on calls to `self.next_back()`
+                // after calling `get_unchecked()`.
+                if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
+                    if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
+                        for _ in 0..sz_a - old_len {
+                            self.a.next_back();
+                        }
                     }
+                    if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
+                        for _ in 0..sz_b - old_len {
+                            self.b.next_back();
+                        }
+                    }
+                    debug_assert_eq!(self.a.size(), self.b.size());
                 }
             }
-        }
-        if self.index < self.len {
-            // since get_unchecked executes code which can panic we increment the counters beforehand
-            // so that the same index won't be accessed twice, as required by TrustedRandomAccess
-            self.len -= 1;
-            self.a_len -= 1;
             let i = self.len;
             // SAFETY: `i` is smaller than the previous value of `self.len`,
             // which is also smaller than or equal to `self.a.len()` and `self.b.len()`
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 32419024db9..6fe5affc48b 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -971,7 +971,7 @@ impl<T> [T] {
     /// assert!(v == [3, 2, 1]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_slice_reverse", issue = "135120")]
+    #[rustc_const_stable(feature = "const_slice_reverse", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn reverse(&mut self) {
         let half_len = self.len() / 2;
@@ -1004,6 +1004,7 @@ impl<T> [T] {
             // this check tells LLVM that the indexing below is
             // in-bounds. Then after inlining -- once the actual
             // lengths of the slices are known -- it's removed.
+            // FIXME(const_trait_impl) replace with let (a, b) = (&mut a[..n], &mut b[..n]);
             let (a, _) = a.split_at_mut(n);
             let (b, _) = b.split_at_mut(n);
 
diff --git a/library/coretests/tests/iter/adapters/cloned.rs b/library/coretests/tests/iter/adapters/cloned.rs
index 78babb7feab..0a3dd1ce46e 100644
--- a/library/coretests/tests/iter/adapters/cloned.rs
+++ b/library/coretests/tests/iter/adapters/cloned.rs
@@ -31,7 +31,8 @@ fn test_cloned_side_effects() {
             .zip(&[1]);
         for _ in iter {}
     }
-    assert_eq!(count, 2);
+    // Zip documentation provides some leeway about side-effects
+    assert!([1, 2].iter().any(|v| *v == count));
 }
 
 #[test]
diff --git a/library/coretests/tests/iter/adapters/zip.rs b/library/coretests/tests/iter/adapters/zip.rs
index 70392dca0fa..063e226a61c 100644
--- a/library/coretests/tests/iter/adapters/zip.rs
+++ b/library/coretests/tests/iter/adapters/zip.rs
@@ -107,9 +107,19 @@ fn test_zip_next_back_side_effects_exhausted() {
     iter.next();
     iter.next();
     iter.next();
-    iter.next();
+    assert_eq!(iter.next(), None);
     assert_eq!(iter.next_back(), None);
-    assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
+
+    assert!(a.starts_with(&[1, 2, 3]));
+    let a_len = a.len();
+    // Tail-side-effects of forward-iteration are "at most one" per next().
+    // And for reverse iteration we don't guarantee much either.
+    // But we can put some bounds on the possible behaviors.
+    assert!(a_len <= 6);
+    assert!(a_len >= 3);
+    a.sort();
+    assert_eq!(a, &[1, 2, 3, 4, 5, 6][..a.len()]);
+
     assert_eq!(b, vec![200, 300, 400]);
 }
 
@@ -120,7 +130,8 @@ fn test_zip_cloned_sideffectful() {
 
     for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
 
-    assert_eq!(&xs, &[1, 1, 1, 0][..]);
+    // Zip documentation permits either case.
+    assert!([&[1, 1, 1, 0], &[1, 1, 0, 0]].iter().any(|v| &xs == *v));
     assert_eq!(&ys, &[1, 1][..]);
 
     let xs = [CountClone::new(), CountClone::new()];
@@ -139,7 +150,8 @@ fn test_zip_map_sideffectful() {
 
     for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
 
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+    // Zip documentation permits either case.
+    assert!([&[1, 1, 1, 1, 1, 0], &[1, 1, 1, 1, 0, 0]].iter().any(|v| &xs == *v));
     assert_eq!(&ys, &[1, 1, 1, 1]);
 
     let mut xs = [0; 4];
@@ -168,7 +180,8 @@ fn test_zip_map_rev_sideffectful() {
 
     {
         let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        (&mut it).take(5).count();
+        // the current impl only trims the tails if the iterator isn't exhausted
+        (&mut it).take(3).count();
         it.next_back();
     }
     assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
@@ -211,9 +224,18 @@ fn test_zip_nth_back_side_effects_exhausted() {
     iter.next();
     iter.next();
     iter.next();
-    iter.next();
+    assert_eq!(iter.next(), None);
     assert_eq!(iter.nth_back(0), None);
-    assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
+    assert!(a.starts_with(&[1, 2, 3]));
+    let a_len = a.len();
+    // Tail-side-effects of forward-iteration are "at most one" per next().
+    // And for reverse iteration we don't guarantee much either.
+    // But we can put some bounds on the possible behaviors.
+    assert!(a_len <= 6);
+    assert!(a_len >= 3);
+    a.sort();
+    assert_eq!(a, &[1, 2, 3, 4, 5, 6][..a.len()]);
+
     assert_eq!(b, vec![200, 300, 400]);
 }
 
@@ -238,32 +260,6 @@ fn test_zip_trusted_random_access_composition() {
 }
 
 #[test]
-#[cfg(panic = "unwind")]
-fn test_zip_trusted_random_access_next_back_drop() {
-    use std::panic::{AssertUnwindSafe, catch_unwind};
-
-    let mut counter = 0;
-
-    let it = [42].iter().map(|e| {
-        let c = counter;
-        counter += 1;
-        if c == 0 {
-            panic!("bomb");
-        }
-
-        e
-    });
-    let it2 = [(); 0].iter();
-    let mut zip = it.zip(it2);
-    catch_unwind(AssertUnwindSafe(|| {
-        zip.next_back();
-    }))
-    .unwrap_err();
-    assert!(zip.next().is_none());
-    assert_eq!(counter, 1);
-}
-
-#[test]
 fn test_double_ended_zip() {
     let xs = [1, 2, 3, 4, 5, 6];
     let ys = [1, 2, 3, 7];
@@ -276,6 +272,63 @@ fn test_double_ended_zip() {
 }
 
 #[test]
+#[cfg(panic = "unwind")]
+/// Regression test for #137255
+/// A previous implementation of Zip TrustedRandomAccess specializations tried to do a lot of work
+/// to preserve side-effects of equalizing the iterator lengths during backwards iteration.
+/// This lead to several cases of unsoundness, twice due to being left in an inconsistent state
+/// after panics.
+/// The new implementation does not try as hard, but we still need panic-safety.
+fn test_nested_zip_panic_safety() {
+    use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
+    use std::sync::atomic::{AtomicUsize, Ordering};
+
+    let mut panic = true;
+    // keeps track of how often element get visited, must be at most once each
+    let witness = [8, 9, 10, 11, 12].map(|i| (i, AtomicUsize::new(0)));
+    let a = witness.as_slice().iter().map(|e| {
+        e.1.fetch_add(1, Ordering::Relaxed);
+        if panic {
+            panic = false;
+            resume_unwind(Box::new(()))
+        }
+        e.0
+    });
+    // shorter than `a`, so `a` will get trimmed
+    let b = [1, 2, 3, 4].as_slice().iter().copied();
+    // shorter still, so `ab` will get trimmed.`
+    let c = [5, 6, 7].as_slice().iter().copied();
+
+    // This will panic during backwards trimming.
+    let ab = zip(a, b);
+    // This being Zip + TrustedRandomAccess means it will only call `next_back``
+    // during trimming and otherwise do calls `__iterator_get_unchecked` on `ab`.
+    let mut abc = zip(ab, c);
+
+    assert_eq!(abc.len(), 3);
+    // This will first trigger backwards trimming before it would normally obtain the
+    // actual element if it weren't for the panic.
+    // This used to corrupt the internal state of `abc`, which then lead to
+    // TrustedRandomAccess safety contract violations in calls to  `ab`,
+    // which ultimately lead to UB.
+    catch_unwind(AssertUnwindSafe(|| abc.next_back())).ok();
+    // check for sane outward behavior after the panic, which indicates a sane internal state.
+    // Technically these outcomes are not required because a panic frees us from correctness obligations.
+    assert_eq!(abc.len(), 2);
+    assert_eq!(abc.next(), Some(((8, 1), 5)));
+    assert_eq!(abc.next_back(), Some(((9, 2), 6)));
+    for (i, (_, w)) in witness.iter().enumerate() {
+        let v = w.load(Ordering::Relaxed);
+        // required by TRA contract
+        assert!(v <= 1, "expected idx {i} to be visited at most once, actual: {v}");
+    }
+    // Trimming panicked and should only run once, so this one won't be visited.
+    // Implementation detail, but not trying to run it again is what keeps
+    // things simple.
+    assert_eq!(witness[3].1.load(Ordering::Relaxed), 0);
+}
+
+#[test]
 fn test_issue_82282() {
     fn overflowed_zip(arr: &[i32]) -> impl Iterator<Item = (i32, &())> {
         static UNIT_EMPTY_ARR: [(); 0] = [];
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index 6ce4c6d62fa..2965174b45b 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -105,7 +105,7 @@ build/
       debuginfo/
       ...
 
-    # Bootstrap host tools (which are always compiled with the stage0 compiler)
+    # Host tools (which are always compiled with the stage0 compiler)
     # are stored here.
     bootstrap-tools/
 
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index d8c6be78247..40e08361a0f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -8,6 +8,7 @@ import re
 import shutil
 import subprocess
 import sys
+import sysconfig
 import tarfile
 import tempfile
 
@@ -333,7 +334,11 @@ def default_build_triple(verbose):
         if ostype == "Android":
             kernel = "linux-android"
         else:
-            kernel = "unknown-linux-gnu"
+            python_soabi = sysconfig.get_config_var("SOABI")
+            if python_soabi is not None and "musl" in python_soabi:
+                kernel = "unknown-linux-musl"
+            else:
+                kernel = "unknown-linux-gnu"
     elif kernel == "SunOS":
         kernel = "pc-solaris"
         # On Solaris, uname -m will return a machine classification instead
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 3278b55305c..1d30886a86a 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -4,7 +4,10 @@ use crate::core::build_steps::compile::{
     add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
 };
 use crate::core::build_steps::tool;
-use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
+use crate::core::build_steps::tool::{
+    COMPILETEST_ALLOW_FEATURES, SourceType, ToolTargetBuildMode, get_tool_target_compiler,
+    prepare_tool_cargo,
+};
 use crate::core::builder::{
     self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
 };
@@ -252,8 +255,10 @@ fn prepare_compiler_for_check(
     mode: Mode,
 ) -> Compiler {
     let host = builder.host_target;
+
     match mode {
         Mode::ToolBootstrap => builder.compiler(0, host),
+        Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
         Mode::ToolStd => {
             if builder.config.compile_time_deps {
                 // When --compile-time-deps is passed, we can't use any rustc
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 09bb2e35bda..85847cac446 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -19,7 +19,7 @@ use serde_derive::Deserialize;
 use tracing::{instrument, span};
 
 use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
-use crate::core::build_steps::tool::SourceType;
+use crate::core::build_steps::tool::{SourceType, copy_lld_artifacts};
 use crate::core::build_steps::{dist, llvm};
 use crate::core::builder;
 use crate::core::builder::{
@@ -2050,19 +2050,20 @@ impl Step for Assemble {
             }
         }
 
-        let maybe_install_llvm_bitcode_linker = |compiler| {
+        let maybe_install_llvm_bitcode_linker = || {
             if builder.config.llvm_bitcode_linker_enabled {
                 trace!("llvm-bitcode-linker enabled, installing");
-                let llvm_bitcode_linker =
-                    builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker {
-                        build_compiler: compiler,
-                        target: target_compiler.host,
-                    });
+                let llvm_bitcode_linker = builder.ensure(
+                    crate::core::build_steps::tool::LlvmBitcodeLinker::from_target_compiler(
+                        builder,
+                        target_compiler,
+                    ),
+                );
 
                 // Copy the llvm-bitcode-linker to the self-contained binary directory
                 let bindir_self_contained = builder
-                    .sysroot(compiler)
-                    .join(format!("lib/rustlib/{}/bin/self-contained", compiler.host));
+                    .sysroot(target_compiler)
+                    .join(format!("lib/rustlib/{}/bin/self-contained", target_compiler.host));
                 let tool_exe = exe("llvm-bitcode-linker", target_compiler.host);
 
                 t!(fs::create_dir_all(&bindir_self_contained));
@@ -2089,9 +2090,9 @@ impl Step for Assemble {
                 builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage = target_compiler.stage));
             }
 
-            let mut precompiled_compiler = target_compiler;
-            precompiled_compiler.forced_compiler(true);
-            maybe_install_llvm_bitcode_linker(precompiled_compiler);
+            // FIXME: this is incomplete, we do not copy a bunch of other stuff to the downloaded
+            // sysroot...
+            maybe_install_llvm_bitcode_linker();
 
             return target_compiler;
         }
@@ -2256,10 +2257,12 @@ impl Step for Assemble {
         copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler);
 
         if builder.config.lld_enabled {
-            builder.ensure(crate::core::build_steps::tool::LldWrapper {
-                build_compiler,
-                target_compiler,
-            });
+            let lld_wrapper =
+                builder.ensure(crate::core::build_steps::tool::LldWrapper::for_use_by_compiler(
+                    builder,
+                    target_compiler,
+                ));
+            copy_lld_artifacts(builder, lld_wrapper, target_compiler);
         }
 
         if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
@@ -2284,15 +2287,14 @@ impl Step for Assemble {
         }
 
         // In addition to `rust-lld` also install `wasm-component-ld` when
-        // LLD is enabled. This is a relatively small binary that primarily
-        // delegates to the `rust-lld` binary for linking and then runs
-        // logic to create the final binary. This is used by the
-        // `wasm32-wasip2` target of Rust.
+        // is enabled. This is used by the `wasm32-wasip2` target of Rust.
         if builder.tool_enabled("wasm-component-ld") {
-            let wasm_component = builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
-                compiler: build_compiler,
-                target: target_compiler.host,
-            });
+            let wasm_component = builder.ensure(
+                crate::core::build_steps::tool::WasmComponentLd::for_use_by_compiler(
+                    builder,
+                    target_compiler,
+                ),
+            );
             builder.copy_link(
                 &wasm_component.tool_path,
                 &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()),
@@ -2300,7 +2302,7 @@ impl Step for Assemble {
             );
         }
 
-        maybe_install_llvm_bitcode_linker(target_compiler);
+        maybe_install_llvm_bitcode_linker();
 
         // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
         // so that it can be found when the newly built `rustc` is run.
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 8b2d65ace50..39e4fb2ac01 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1575,7 +1575,10 @@ impl Step for Extended {
             compiler: builder.compiler(stage, target),
             backend: "cranelift".to_string(),
         });
-        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target});
+        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
+            build_compiler: compiler,
+            target
+        });
 
         let etc = builder.src.join("src/etc/installer");
 
@@ -2341,9 +2344,13 @@ impl Step for LlvmTools {
     }
 }
 
+/// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host
+/// is `target`.
 #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
 pub struct LlvmBitcodeLinker {
-    pub compiler: Compiler,
+    /// The linker will be compiled by this compiler.
+    pub build_compiler: Compiler,
+    /// The linker will by usable by rustc on this host.
     pub target: TargetSelection,
 }
 
@@ -2359,9 +2366,8 @@ impl Step for LlvmBitcodeLinker {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(LlvmBitcodeLinker {
-            compiler: run.builder.compiler_for(
-                run.builder.top_stage,
-                run.builder.config.host_target,
+            build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target(
+                run.builder,
                 run.target,
             ),
             target: run.target,
@@ -2369,13 +2375,10 @@ impl Step for LlvmBitcodeLinker {
     }
 
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
-        let compiler = self.compiler;
         let target = self.target;
 
-        builder.ensure(compile::Rustc::new(compiler, target));
-
-        let llbc_linker =
-            builder.ensure(tool::LlvmBitcodeLinker { build_compiler: compiler, target });
+        let llbc_linker = builder
+            .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target));
 
         let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
 
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 4434d6658eb..4156b49a8b3 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -287,7 +287,7 @@ install!((self, builder, _config),
         }
     };
     LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, {
-        if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) {
+        if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { build_compiler: self.compiler, target: self.target }) {
             install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball);
         } else {
             builder.info(
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 9e7ea5c115f..98f11116279 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2945,7 +2945,8 @@ impl Step for RemoteCopyLibs {
 
         builder.info(&format!("REMOTE copy libs to emulator ({target})"));
 
-        let remote_test_server = builder.ensure(tool::RemoteTestServer { compiler, target });
+        let remote_test_server =
+            builder.ensure(tool::RemoteTestServer { build_compiler: compiler, target });
 
         // Spawn the emulator and wait for it to come online
         let tool = builder.tool_exe(Tool::RemoteTestClient);
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 1c994b0ccfc..f5fa33b98f3 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -42,7 +42,8 @@ pub enum ToolArtifactKind {
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 struct ToolBuild {
-    compiler: Compiler,
+    /// Compiler that will build this tool.
+    build_compiler: Compiler,
     target: TargetSelection,
     tool: &'static str,
     path: &'static str,
@@ -112,34 +113,34 @@ impl Step for ToolBuild {
         let mut tool = self.tool;
         let path = self.path;
 
-        let target_compiler = self.compiler;
-        self.compiler = if self.mode == Mode::ToolRustc {
-            get_tool_rustc_compiler(builder, self.compiler)
+        let target_compiler = self.build_compiler;
+        self.build_compiler = if self.mode == Mode::ToolRustc {
+            get_tool_rustc_compiler(builder, self.build_compiler)
         } else {
-            self.compiler
+            self.build_compiler
         };
 
         match self.mode {
             Mode::ToolRustc => {
                 // If compiler was forced, its artifacts should have been prepared earlier.
-                if !self.compiler.is_forced_compiler() {
-                    builder.std(self.compiler, self.compiler.host);
-                    builder.ensure(compile::Rustc::new(self.compiler, target));
+                if !self.build_compiler.is_forced_compiler() {
+                    builder.std(self.build_compiler, self.build_compiler.host);
+                    builder.ensure(compile::Rustc::new(self.build_compiler, target));
                 }
             }
             Mode::ToolStd => {
                 // If compiler was forced, its artifacts should have been prepared earlier.
-                if !self.compiler.is_forced_compiler() {
-                    builder.std(self.compiler, target)
+                if !self.build_compiler.is_forced_compiler() {
+                    builder.std(self.build_compiler, target);
                 }
             }
-            Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
+            Mode::ToolBootstrap | Mode::ToolTarget => {} // uses downloaded stage0 compiler libs
             _ => panic!("unexpected Mode for tool build"),
         }
 
         let mut cargo = prepare_tool_cargo(
             builder,
-            self.compiler,
+            self.build_compiler,
             self.mode,
             target,
             Kind::Build,
@@ -161,7 +162,7 @@ impl Step for ToolBuild {
 
         // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
         // could use the additional optimizations.
-        if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) {
+        if self.mode == Mode::ToolRustc && is_lto_stage(&self.build_compiler) {
             let lto = match builder.config.rust_lto {
                 RustcLto::Off => Some("off"),
                 RustcLto::Thin => Some("thin"),
@@ -183,8 +184,9 @@ impl Step for ToolBuild {
             Kind::Build,
             self.mode,
             self.tool,
-            self.compiler.stage,
-            &self.compiler.host,
+            // A stage N tool is built with the stage N-1 compiler.
+            self.build_compiler.stage + 1,
+            &self.build_compiler.host,
             &self.target,
         );
 
@@ -207,14 +209,14 @@ impl Step for ToolBuild {
             }
             let tool_path = match self.artifact_kind {
                 ToolArtifactKind::Binary => {
-                    copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool)
+                    copy_link_tool_bin(builder, self.build_compiler, self.target, self.mode, tool)
                 }
                 ToolArtifactKind::Library => builder
-                    .cargo_out(self.compiler, self.mode, self.target)
+                    .cargo_out(self.build_compiler, self.mode, self.target)
                     .join(format!("lib{tool}.rlib")),
             };
 
-            ToolBuildResult { tool_path, build_compiler: self.compiler, target_compiler }
+            ToolBuildResult { tool_path, build_compiler: self.build_compiler, target_compiler }
         }
     }
 }
@@ -365,6 +367,47 @@ pub(crate) fn get_tool_rustc_compiler(
     builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target)
 }
 
+/// Determines how to build a `ToolTarget`, i.e. which compiler should be used to compile it.
+/// The compiler stage is automatically bumped if we need to cross-compile a stage 1 tool.
+pub enum ToolTargetBuildMode {
+    /// Build the tool using rustc that corresponds to the selected CLI stage.
+    Build(TargetSelection),
+    /// Build the tool so that it can be attached to the sysroot of the passed compiler.
+    /// Since we always dist stage 2+, the compiler that builds the tool in this case has to be
+    /// stage 1+.
+    Dist(Compiler),
+}
+
+/// Returns compiler that is able to compile a `ToolTarget` tool with the given `mode`.
+pub(crate) fn get_tool_target_compiler(
+    builder: &Builder<'_>,
+    mode: ToolTargetBuildMode,
+) -> Compiler {
+    let (target, build_compiler_stage) = match mode {
+        ToolTargetBuildMode::Build(target) => {
+            assert!(builder.top_stage > 0);
+            // If we want to build a stage N tool, we need to compile it with stage N-1 rustc
+            (target, builder.top_stage - 1)
+        }
+        ToolTargetBuildMode::Dist(target_compiler) => {
+            assert!(target_compiler.stage > 0);
+            // If we want to dist a stage N rustc, we want to attach stage N tool to it.
+            // And to build that tool, we need to compile it with stage N-1 rustc
+            (target_compiler.host, target_compiler.stage - 1)
+        }
+    };
+
+    let compiler = if builder.host_target == target {
+        builder.compiler(build_compiler_stage, builder.host_target)
+    } else {
+        // If we are cross-compiling a stage 1 tool, we cannot do that with a stage 0 compiler,
+        // so we auto-bump the tool's stage to 2, which means we need a stage 1 compiler.
+        builder.compiler(build_compiler_stage.max(1), builder.host_target)
+    };
+    builder.std(compiler, target);
+    compiler
+}
+
 /// Links a built tool binary with the given `name` from the build directory to the
 /// tools directory.
 fn copy_link_tool_bin(
@@ -451,7 +494,7 @@ macro_rules! bootstrap_tool {
                 let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest;
 
                 builder.ensure(ToolBuild {
-                    compiler: self.compiler,
+                    build_compiler: self.compiler,
                     target: self.target,
                     tool: $tool_name,
                     mode: if is_unstable && !compiletest_wants_stage0 {
@@ -521,7 +564,6 @@ bootstrap_tool!(
     // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
     RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
     CoverageDump, "src/tools/coverage-dump", "coverage-dump";
-    WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
     UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
     FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump";
     OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"];
@@ -560,7 +602,7 @@ impl Step for RustcPerf {
         builder.require_submodule("src/tools/rustc-perf", None);
 
         let tool = ToolBuild {
-            compiler: self.compiler,
+            build_compiler: self.compiler,
             target: self.target,
             tool: "collector",
             mode: Mode::ToolBootstrap,
@@ -576,7 +618,7 @@ impl Step for RustcPerf {
         let res = builder.ensure(tool.clone());
         // We also need to symlink the `rustc-fake` binary to the corresponding directory,
         // because `collector` expects it in the same directory.
-        copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake");
+        copy_link_tool_bin(builder, tool.build_compiler, tool.target, tool.mode, "rustc-fake");
 
         res
     }
@@ -620,7 +662,7 @@ impl Step for ErrorIndex {
 
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
         builder.ensure(ToolBuild {
-            compiler: self.compiler,
+            build_compiler: self.compiler,
             target: self.compiler.host,
             tool: "error_index_generator",
             mode: Mode::ToolRustc,
@@ -636,7 +678,7 @@ impl Step for ErrorIndex {
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct RemoteTestServer {
-    pub compiler: Compiler,
+    pub build_compiler: Compiler,
     pub target: TargetSelection,
 }
 
@@ -649,17 +691,20 @@ impl Step for RemoteTestServer {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(RemoteTestServer {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
+            build_compiler: get_tool_target_compiler(
+                run.builder,
+                ToolTargetBuildMode::Build(run.target),
+            ),
             target: run.target,
         });
     }
 
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
         builder.ensure(ToolBuild {
-            compiler: self.compiler,
+            build_compiler: self.build_compiler,
             target: self.target,
             tool: "remote-test-server",
-            mode: Mode::ToolStd,
+            mode: Mode::ToolTarget,
             path: "src/tools/remote-test-server",
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
@@ -668,6 +713,10 @@ impl Step for RemoteTestServer {
             artifact_kind: ToolArtifactKind::Binary,
         })
     }
+
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::build("remote-test-server", self.target).built_by(self.build_compiler))
+    }
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
@@ -757,7 +806,7 @@ impl Step for Rustdoc {
 
         let ToolBuildResult { tool_path, build_compiler, target_compiler } =
             builder.ensure(ToolBuild {
-                compiler: target_compiler,
+                build_compiler: target_compiler,
                 target,
                 // Cargo adds a number of paths to the dylib search path on windows, which results in
                 // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
@@ -825,7 +874,7 @@ impl Step for Cargo {
         builder.build.require_submodule("src/tools/cargo", None);
 
         builder.ensure(ToolBuild {
-            compiler: self.compiler,
+            build_compiler: self.compiler,
             target: self.target,
             tool: "cargo",
             mode: Mode::ToolRustc,
@@ -839,17 +888,50 @@ impl Step for Cargo {
     }
 }
 
+/// Represents a built LldWrapper, the `lld-wrapper` tool itself, and a directory
+/// containing a build of LLD.
+#[derive(Clone)]
+pub struct BuiltLldWrapper {
+    tool: ToolBuildResult,
+    lld_dir: PathBuf,
+}
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct LldWrapper {
     pub build_compiler: Compiler,
-    pub target_compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl LldWrapper {
+    /// Returns `LldWrapper` that should be **used** by the passed compiler.
+    pub fn for_use_by_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self {
+        Self {
+            build_compiler: get_tool_target_compiler(
+                builder,
+                ToolTargetBuildMode::Dist(target_compiler),
+            ),
+            target: target_compiler.host,
+        }
+    }
 }
 
 impl Step for LldWrapper {
-    type Output = ToolBuildResult;
+    type Output = BuiltLldWrapper;
+
+    const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.never()
+        run.path("src/tools/lld-wrapper")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(LldWrapper {
+            build_compiler: get_tool_target_compiler(
+                run.builder,
+                ToolTargetBuildMode::Build(run.target),
+            ),
+            target: run.target,
+        });
     }
 
     #[cfg_attr(
@@ -858,25 +940,16 @@ impl Step for LldWrapper {
             level = "debug",
             name = "LldWrapper::run",
             skip_all,
-            fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler),
+            fields(build_compiler = ?self.build_compiler),
         ),
     )]
-    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
-        if builder.config.dry_run() {
-            return ToolBuildResult {
-                tool_path: Default::default(),
-                build_compiler: self.build_compiler,
-                target_compiler: self.target_compiler,
-            };
-        }
-
-        let target = self.target_compiler.host;
-
-        let tool_result = builder.ensure(ToolBuild {
-            compiler: self.build_compiler,
-            target,
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let lld_dir = builder.ensure(llvm::Lld { target: self.target });
+        let tool = builder.ensure(ToolBuild {
+            build_compiler: self.build_compiler,
+            target: self.target,
             tool: "lld-wrapper",
-            mode: Mode::ToolStd,
+            mode: Mode::ToolTarget,
             path: "src/tools/lld-wrapper",
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
@@ -884,38 +957,110 @@ impl Step for LldWrapper {
             cargo_args: Vec::new(),
             artifact_kind: ToolArtifactKind::Binary,
         });
+        BuiltLldWrapper { tool, lld_dir }
+    }
 
-        let libdir_bin = builder.sysroot_target_bindir(self.target_compiler, target);
-        t!(fs::create_dir_all(&libdir_bin));
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::build("LldWrapper", self.target).built_by(self.build_compiler))
+    }
+}
 
-        let lld_install = builder.ensure(llvm::Lld { target });
-        let src_exe = exe("lld", target);
-        let dst_exe = exe("rust-lld", target);
+pub(crate) fn copy_lld_artifacts(
+    builder: &Builder<'_>,
+    lld_wrapper: BuiltLldWrapper,
+    target_compiler: Compiler,
+) {
+    let target = target_compiler.host;
 
+    let libdir_bin = builder.sysroot_target_bindir(target_compiler, target);
+    t!(fs::create_dir_all(&libdir_bin));
+
+    let src_exe = exe("lld", target);
+    let dst_exe = exe("rust-lld", target);
+
+    builder.copy_link(
+        &lld_wrapper.lld_dir.join("bin").join(src_exe),
+        &libdir_bin.join(dst_exe),
+        FileType::Executable,
+    );
+    let self_contained_lld_dir = libdir_bin.join("gcc-ld");
+    t!(fs::create_dir_all(&self_contained_lld_dir));
+
+    for name in crate::LLD_FILE_NAMES {
         builder.copy_link(
-            &lld_install.join("bin").join(src_exe),
-            &libdir_bin.join(dst_exe),
+            &lld_wrapper.tool.tool_path,
+            &self_contained_lld_dir.join(exe(name, target)),
             FileType::Executable,
         );
-        let self_contained_lld_dir = libdir_bin.join("gcc-ld");
-        t!(fs::create_dir_all(&self_contained_lld_dir));
-
-        for name in crate::LLD_FILE_NAMES {
-            builder.copy_link(
-                &tool_result.tool_path,
-                &self_contained_lld_dir.join(exe(name, target)),
-                FileType::Executable,
-            );
+    }
+}
+
+/// Builds the `wasm-component-ld` linker wrapper, which is shipped with rustc to be executed on the
+/// host platform where rustc runs.
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct WasmComponentLd {
+    build_compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl WasmComponentLd {
+    /// Returns `WasmComponentLd` that should be **used** by the passed compiler.
+    pub fn for_use_by_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self {
+        Self {
+            build_compiler: get_tool_target_compiler(
+                builder,
+                ToolTargetBuildMode::Dist(target_compiler),
+            ),
+            target: target_compiler.host,
         }
+    }
+}
+
+impl Step for WasmComponentLd {
+    type Output = ToolBuildResult;
+
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/wasm-component-ld")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(WasmComponentLd {
+            build_compiler: get_tool_target_compiler(
+                run.builder,
+                ToolTargetBuildMode::Build(run.target),
+            ),
+            target: run.target,
+        });
+    }
 
-        tool_result
+    #[cfg_attr(
+        feature = "tracing",
+        instrument(
+            level = "debug",
+            name = "WasmComponentLd::run",
+            skip_all,
+            fields(build_compiler = ?self.build_compiler),
+        ),
+    )]
+    fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
+        builder.ensure(ToolBuild {
+            build_compiler: self.build_compiler,
+            target: self.target,
+            tool: "wasm-component-ld",
+            mode: Mode::ToolTarget,
+            path: "src/tools/wasm-component-ld",
+            source_type: SourceType::InTree,
+            extra_features: vec![],
+            allow_features: "",
+            cargo_args: vec![],
+            artifact_kind: ToolArtifactKind::Binary,
+        })
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        Some(
-            StepMetadata::build("LldWrapper", self.target_compiler.host)
-                .built_by(self.build_compiler),
-        )
+        Some(StepMetadata::build("WasmComponentLd", self.target).built_by(self.build_compiler))
     }
 }
 
@@ -948,7 +1093,7 @@ impl Step for RustAnalyzer {
 
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
         builder.ensure(ToolBuild {
-            compiler: self.compiler,
+            build_compiler: self.compiler,
             target: self.target,
             tool: "rust-analyzer",
             mode: Mode::ToolRustc,
@@ -993,7 +1138,7 @@ impl Step for RustAnalyzerProcMacroSrv {
 
     fn run(self, builder: &Builder<'_>) -> Option<ToolBuildResult> {
         let tool_result = builder.ensure(ToolBuild {
-            compiler: self.compiler,
+            build_compiler: self.compiler,
             target: self.target,
             tool: "rust-analyzer-proc-macro-srv",
             mode: Mode::ToolRustc,
@@ -1021,8 +1166,35 @@ impl Step for RustAnalyzerProcMacroSrv {
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct LlvmBitcodeLinker {
-    pub build_compiler: Compiler,
-    pub target: TargetSelection,
+    build_compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl LlvmBitcodeLinker {
+    /// Returns `LlvmBitcodeLinker` that will be **compiled** by the passed compiler, for the given
+    /// `target`.
+    pub fn from_build_compiler(build_compiler: Compiler, target: TargetSelection) -> Self {
+        Self { build_compiler, target }
+    }
+
+    /// Returns `LlvmBitcodeLinker` that should be **used** by the passed compiler.
+    pub fn from_target_compiler(builder: &Builder<'_>, target_compiler: Compiler) -> Self {
+        Self {
+            build_compiler: get_tool_target_compiler(
+                builder,
+                ToolTargetBuildMode::Dist(target_compiler),
+            ),
+            target: target_compiler.host,
+        }
+    }
+
+    /// Return a compiler that is able to build this tool for the given `target`.
+    pub fn get_build_compiler_for_target(
+        builder: &Builder<'_>,
+        target: TargetSelection,
+    ) -> Compiler {
+        get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target))
+    }
 }
 
 impl Step for LlvmBitcodeLinker {
@@ -1038,9 +1210,7 @@ impl Step for LlvmBitcodeLinker {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(LlvmBitcodeLinker {
-            build_compiler: run
-                .builder
-                .compiler(run.builder.top_stage, run.builder.config.host_target),
+            build_compiler: Self::get_build_compiler_for_target(run.builder, run.target),
             target: run.target,
         });
     }
@@ -1051,10 +1221,10 @@ impl Step for LlvmBitcodeLinker {
     )]
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
         builder.ensure(ToolBuild {
-            compiler: self.build_compiler,
+            build_compiler: self.build_compiler,
             target: self.target,
             tool: "llvm-bitcode-linker",
-            mode: Mode::ToolRustc,
+            mode: Mode::ToolTarget,
             path: "src/tools/llvm-bitcode-linker",
             source_type: SourceType::InTree,
             extra_features: vec![],
@@ -1239,7 +1409,7 @@ fn run_tool_build_step(
 
     let ToolBuildResult { tool_path, build_compiler, target_compiler } =
         builder.ensure(ToolBuild {
-            compiler,
+            build_compiler: compiler,
             target,
             tool: tool_name,
             mode: Mode::ToolRustc,
@@ -1338,7 +1508,7 @@ impl Step for TestFloatParse {
         let compiler = builder.compiler(builder.top_stage, bootstrap_host);
 
         builder.ensure(ToolBuild {
-            compiler,
+            build_compiler: compiler,
             target: bootstrap_host,
             tool: "test-float-parse",
             mode: Mode::ToolStd,
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index a3b471ca56e..badd5f24dba 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -537,7 +537,7 @@ impl Builder<'_> {
             }
         }
 
-        let stage = if compiler.stage == 0 && self.local_rebuild {
+        let build_compiler_stage = if compiler.stage == 0 && self.local_rebuild {
             // Assume the local-rebuild rustc already has stage1 features.
             1
         } else {
@@ -545,15 +545,17 @@ impl Builder<'_> {
         };
 
         // We synthetically interpret a stage0 compiler used to build tools as a
-        // "raw" compiler in that it's the exact snapshot we download. Normally
-        // the stage0 build means it uses libraries build by the stage0
-        // compiler, but for tools we just use the precompiled libraries that
-        // we've downloaded
-        let use_snapshot = mode == Mode::ToolBootstrap;
-        assert!(!use_snapshot || stage == 0 || self.local_rebuild);
-
-        let maybe_sysroot = self.sysroot(compiler);
-        let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
+        // "raw" compiler in that it's the exact snapshot we download. For things like
+        // ToolRustc, we would have to use the artificial stage0-sysroot compiler instead.
+        let use_snapshot =
+            mode == Mode::ToolBootstrap || (mode == Mode::ToolTarget && build_compiler_stage == 0);
+        assert!(!use_snapshot || build_compiler_stage == 0 || self.local_rebuild);
+
+        let sysroot = if use_snapshot {
+            self.rustc_snapshot_sysroot().to_path_buf()
+        } else {
+            self.sysroot(compiler)
+        };
         let libdir = self.rustc_libdir(compiler);
 
         let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
@@ -562,7 +564,7 @@ impl Builder<'_> {
         }
 
         let mut rustflags = Rustflags::new(target);
-        if stage != 0 {
+        if build_compiler_stage != 0 {
             if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
                 cargo.args(s.split_whitespace());
             }
@@ -604,7 +606,7 @@ impl Builder<'_> {
         // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
         // library unnecessary. This can be removed when windows-rs enables raw-dylib
         // unconditionally.
-        if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode {
+        if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap | Mode::ToolTarget = mode {
             rustflags.arg("--cfg=windows_raw_dylib");
         }
 
@@ -657,7 +659,7 @@ impl Builder<'_> {
         // FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments
         // to the host invocation here, but rather Cargo should know what flags to pass rustc
         // itself.
-        if stage == 0 {
+        if build_compiler_stage == 0 {
             hostflags.arg("--cfg=bootstrap");
         }
 
@@ -666,7 +668,7 @@ impl Builder<'_> {
         // #71458.
         let mut rustdocflags = rustflags.clone();
         rustdocflags.propagate_cargo_env("RUSTDOCFLAGS");
-        if stage == 0 {
+        if build_compiler_stage == 0 {
             rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP");
         } else {
             rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP");
@@ -677,7 +679,7 @@ impl Builder<'_> {
         }
 
         match mode {
-            Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
+            Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {}
             Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
                 // Build proc macros both for the host and the target unless proc-macros are not
                 // supported by the target.
@@ -719,7 +721,7 @@ impl Builder<'_> {
         // feature on the rustc side.
         cargo.arg("-Zbinary-dep-depinfo");
         let allow_features = match mode {
-            Mode::ToolBootstrap | Mode::ToolStd => {
+            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {
                 // Restrict the allowed features so we don't depend on nightly
                 // accidentally.
                 //
@@ -833,7 +835,7 @@ impl Builder<'_> {
         cargo
             .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
             .env("RUSTC_REAL", self.rustc(compiler))
-            .env("RUSTC_STAGE", stage.to_string())
+            .env("RUSTC_STAGE", build_compiler_stage.to_string())
             .env("RUSTC_SYSROOT", sysroot)
             .env("RUSTC_LIBDIR", libdir)
             .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
@@ -878,7 +880,7 @@ impl Builder<'_> {
         let debuginfo_level = match mode {
             Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
             Mode::Std => self.config.rust_debuginfo_level_std,
-            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
+            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
                 self.config.rust_debuginfo_level_tools
             }
         };
@@ -890,11 +892,10 @@ impl Builder<'_> {
             profile_var("DEBUG_ASSERTIONS"),
             match mode {
                 Mode::Std => self.config.std_debug_assertions,
-                Mode::Rustc => self.config.rustc_debug_assertions,
-                Mode::Codegen => self.config.rustc_debug_assertions,
-                Mode::ToolBootstrap => self.config.tools_debug_assertions,
-                Mode::ToolStd => self.config.tools_debug_assertions,
-                Mode::ToolRustc => self.config.tools_debug_assertions,
+                Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions,
+                Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
+                    self.config.tools_debug_assertions
+                }
             }
             .to_string(),
         );
@@ -965,7 +966,11 @@ impl Builder<'_> {
                     cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to);
                 }
             }
-            Mode::Std | Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => {
+            Mode::Std
+            | Mode::ToolBootstrap
+            | Mode::ToolRustc
+            | Mode::ToolStd
+            | Mode::ToolTarget => {
                 if let Some(ref map_to) =
                     self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler)
                 {
@@ -1280,7 +1285,7 @@ impl Builder<'_> {
             };
 
             if let Some(limit) = limit
-                && (stage == 0
+                && (build_compiler_stage == 0
                     || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm")
             {
                 rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 1b75d00b30e..d73e2bce25b 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -963,6 +963,7 @@ impl<'a> Builder<'a> {
                 tool::RemoteTestServer,
                 tool::RemoteTestClient,
                 tool::RustInstaller,
+                tool::FeaturesStatusDump,
                 tool::Cargo,
                 tool::RustAnalyzer,
                 tool::RustAnalyzerProcMacroSrv,
@@ -984,6 +985,8 @@ impl<'a> Builder<'a> {
                 tool::CoverageDump,
                 tool::LlvmBitcodeLinker,
                 tool::RustcPerf,
+                tool::WasmComponentLd,
+                tool::LldWrapper
             ),
             Kind::Clippy => describe!(
                 clippy::Std,
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 51a90649692..2f8cdd2f8c8 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -769,11 +769,11 @@ mod snapshot {
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 0 <host> -> LldWrapper 1 <host>
-        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
+        [build] rustc 0 <host> -> LlvmBitcodeLinker 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
         [build] rustc 1 <host> -> rustc 2 <host>
         [build] rustc 1 <host> -> LldWrapper 2 <host>
-        [build] rustc 2 <host> -> LlvmBitcodeLinker 3 <host>
+        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
         [build] rustc 2 <host> -> std 2 <host>
         [build] rustdoc 1 <host>
         "
@@ -793,17 +793,17 @@ mod snapshot {
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 0 <host> -> LldWrapper 1 <host>
-        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
+        [build] rustc 0 <host> -> LlvmBitcodeLinker 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
         [build] rustc 1 <host> -> rustc 2 <host>
         [build] rustc 1 <host> -> LldWrapper 2 <host>
-        [build] rustc 2 <host> -> LlvmBitcodeLinker 3 <host>
+        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
         [build] rustc 1 <host> -> std 1 <target1>
         [build] rustc 2 <host> -> std 2 <target1>
         [build] llvm <target1>
         [build] rustc 1 <host> -> rustc 2 <target1>
         [build] rustc 1 <host> -> LldWrapper 2 <target1>
-        [build] rustc 2 <target1> -> LlvmBitcodeLinker 3 <target1>
+        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <target1>
         [build] rustdoc 1 <target1>
         "
         );
@@ -1062,18 +1062,28 @@ mod snapshot {
     fn dist_extended() {
         let ctx = TestCtx::new();
         insta::assert_snapshot!(
-            ctx
-                .config("dist")
-                .args(&["--set", "build.extended=true"])
-                .render_steps(), @r"
+            ctx.config("dist")
+            .args(&[
+                "--set",
+                "build.extended=true",
+                "--set",
+                "rust.llvm-bitcode-linker=true",
+                "--set",
+                "rust.lld=true",
+            ])
+            .render_steps(), @r"
         [build] rustc 0 <host> -> UnstableBookGen 1 <host>
         [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 0 <host> -> LldWrapper 1 <host>
         [build] rustc 0 <host> -> WasmComponentLd 1 <host>
+        [build] rustc 0 <host> -> LlvmBitcodeLinker 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
         [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 1 <host> -> LldWrapper 2 <host>
         [build] rustc 1 <host> -> WasmComponentLd 2 <host>
+        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
         [build] rustdoc 1 <host>
         [doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
         [build] rustc 2 <host> -> std 2 <host>
@@ -1092,7 +1102,6 @@ mod snapshot {
         [build] rustc 0 <host> -> cargo-clippy 1 <host>
         [build] rustc 0 <host> -> miri 1 <host>
         [build] rustc 0 <host> -> cargo-miri 1 <host>
-        [build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
         ");
     }
 
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 44be51815c7..63aab4d116a 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -253,12 +253,24 @@ pub enum Mode {
     /// These tools are intended to be only executed on the host system that
     /// invokes bootstrap, and they thus cannot be cross-compiled.
     ///
-    /// They are always built using the stage0 compiler, and typically they
+    /// They are always built using the stage0 compiler, and they
     /// can be compiled with stable Rust.
     ///
     /// These tools also essentially do not participate in staging.
     ToolBootstrap,
 
+    /// Build a cross-compilable helper tool. These tools do not depend on unstable features or
+    /// compiler internals, but they might be cross-compilable (so we cannot build them using the
+    /// stage0 compiler, unlike `ToolBootstrap`).
+    ///
+    /// Some of these tools are also shipped in our `dist` archives.
+    /// While we could compile them using the stage0 compiler when not cross-compiling, we instead
+    /// use the in-tree compiler (and std) to build them, so that we can ship e.g. std security
+    /// fixes and avoid depending fully on stage0 for the artifacts that we ship.
+    ///
+    /// This mode is used e.g. for linkers and linker tools invoked by rustc on its host target.
+    ToolTarget,
+
     /// Build a tool which uses the locally built std, placing output in the
     /// "stageN-tools" directory. Its usage is quite rare, mainly used by
     /// compiletest which needs libtest.
@@ -273,11 +285,21 @@ pub enum Mode {
 
 impl Mode {
     pub fn is_tool(&self) -> bool {
-        matches!(self, Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd)
+        match self {
+            Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd | Mode::ToolTarget => true,
+            Mode::Std | Mode::Codegen | Mode::Rustc => false,
+        }
     }
 
     pub fn must_support_dlopen(&self) -> bool {
-        matches!(self, Mode::Std | Mode::Codegen)
+        match self {
+            Mode::Std | Mode::Codegen => true,
+            Mode::ToolBootstrap
+            | Mode::ToolRustc
+            | Mode::ToolStd
+            | Mode::ToolTarget
+            | Mode::Rustc => false,
+        }
     }
 }
 
@@ -802,17 +824,39 @@ impl Build {
     /// stage when running with a particular host compiler.
     ///
     /// The mode indicates what the root directory is for.
-    fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf {
-        let suffix = match mode {
-            Mode::Std => "-std",
-            Mode::Rustc => "-rustc",
-            Mode::Codegen => "-codegen",
-            Mode::ToolBootstrap => {
-                return self.out.join(compiler.host).join("bootstrap-tools");
+    fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf {
+        use std::fmt::Write;
+
+        fn bootstrap_tool() -> (Option<u32>, &'static str) {
+            (None, "bootstrap-tools")
+        }
+        fn staged_tool(build_compiler: Compiler) -> (Option<u32>, &'static str) {
+            (Some(build_compiler.stage), "tools")
+        }
+
+        let (stage, suffix) = match mode {
+            Mode::Std => (Some(build_compiler.stage), "std"),
+            Mode::Rustc => (Some(build_compiler.stage), "rustc"),
+            Mode::Codegen => (Some(build_compiler.stage), "codegen"),
+            Mode::ToolBootstrap => bootstrap_tool(),
+            Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage), "tools"),
+            Mode::ToolTarget => {
+                // If we're not cross-compiling (the common case), share the target directory with
+                // bootstrap tools to reuse the build cache.
+                if build_compiler.stage == 0 {
+                    bootstrap_tool()
+                } else {
+                    staged_tool(build_compiler)
+                }
             }
-            Mode::ToolStd | Mode::ToolRustc => "-tools",
         };
-        self.out.join(compiler.host).join(format!("stage{}{}", compiler.stage, suffix))
+        let path = self.out.join(build_compiler.host);
+        let mut dir_name = String::new();
+        if let Some(stage) = stage {
+            write!(dir_name, "stage{stage}-").unwrap();
+        }
+        dir_name.push_str(suffix);
+        path.join(dir_name)
     }
 
     /// Returns the root output directory for all Cargo output in a given stage,
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index f0c52fe3d1c..0a6ebe44b3d 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -172,9 +172,9 @@ try:
 optional:
   # This job is used just to test optional jobs.
   # It will be replaced by tier 2 and tier 3 jobs in the future.
-  - name: optional-mingw-check-1
+  - name: optional-pr-check-1
     env:
-      IMAGE: mingw-check-1
+      IMAGE: pr-check-1
     <<: *job-linux-4c
 
 # Main CI jobs that have to be green to merge a commit into master
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 63aa08c389c..6685add461e 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -75,8 +75,10 @@ expectations](ui.md#controlling-passfail-expectations).
 | `check-fail`                | Building (no codegen) should fail           | `ui`, `crashes`                           | N/A             |
 | `build-pass`                | Building should pass                        | `ui`, `crashes`, `codegen`, `incremental` | N/A             |
 | `build-fail`                | Building should fail                        | `ui`, `crashes`                           | N/A             |
-| `run-pass`                  | Running the test binary should pass         | `ui`, `crashes`, `incremental`            | N/A             |
-| `run-fail`                  | Running the test binary should fail         | `ui`, `crashes`                           | N/A             |
+| `run-pass`                  | Program must exit with code `0`             | `ui`, `crashes`, `incremental`            | N/A             |
+| `run-fail`                  | Program must exit with code `1..=127`       | `ui`, `crashes`                           | N/A             |
+| `run-crash`                 | Program must crash                          | `ui`                                      | N/A             |
+| `run-fail-or-crash`         | Program must `run-fail` or `run-crash`      | `ui`                                      | N/A             |
 | `ignore-pass`               | Ignore `--pass` flag                        | `ui`, `crashes`, `codegen`, `incremental` | N/A             |
 | `dont-check-failure-status` | Don't check exact failure status (i.e. `1`) | `ui`, `incremental`                       | N/A             |
 | `failure-status`            | Check                                       | `ui`, `crashes`                           | Any `u16`       |
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index 4fce5838b6e..9bfc60e08a6 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -448,7 +448,7 @@ even run the resulting program. Just add one of the following
   - `//@ build-pass` — compilation and linking should succeed but do
     not run the resulting binary.
   - `//@ run-pass` — compilation should succeed and running the resulting
-    binary should also succeed.
+    binary should make it exit with code 0 which indicates success.
 - Fail directives:
   - `//@ check-fail` — compilation should fail (the codegen phase is skipped).
     This is the default for UI tests.
@@ -457,10 +457,20 @@ even run the resulting program. Just add one of the following
     - First time is to ensure that the compile succeeds without the codegen phase
     - Second time is to ensure that the full compile fails
   - `//@ run-fail` — compilation should succeed, but running the resulting
-    binary should fail.
-
-For `run-pass` and `run-fail` tests, by default the output of the program itself
-is not checked.
+    binary should make it exit with a code in the range `1..=127` which
+    indicates regular failure. On targets without unwind support, crashes
+    are also accepted.
+  - `//@ run-crash` — compilation should succeed, but running the resulting
+    binary should fail with a crash. Crashing is defined as "not exiting with
+    a code in the range `0..=127`". Example on Linux: Termination by `SIGABRT`
+    or `SIGSEGV`. Example on Windows: Exiting with the code for
+    `STATUS_ILLEGAL_INSTRUCTION` (`0xC000001D`).
+  - `//@ run-fail-or-crash` — compilation should succeed, but running the
+    resulting binary should either `run-fail` or `run-crash`. Useful if a test
+    crashes on some targets but just fails on others.
+
+For `run-pass`. `run-fail`, `run-crash` and `run-fail-or-crash` tests, by
+default the output of the program itself is not checked.
 
 If you want to check the output of running the program, include the
 `check-run-results` directive. This will check for a `.run.stderr` and
diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md
index f8bafe03214..c80d7d8743c 100644
--- a/src/doc/rustc/src/exploit-mitigations.md
+++ b/src/doc/rustc/src/exploit-mitigations.md
@@ -54,17 +54,17 @@ Summary of exploit mitigations supported by the Rust compiler when building
 programs for the Linux operating system on the AMD64 architecture and
 equivalent.
 
-| Exploit mitigation | Supported and enabled by default | Since |
-| - | - | - |
-| Position-independent executable | Yes | 0.12.0 (2014-10-09) |
-| Integer overflow checks | Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) |
-| Non-executable memory regions | Yes | 1.8.0 (2016-04-14) |
-| Stack clashing protection | Yes | 1.20.0 (2017-08-31) |
-| Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) |
-| Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) |
-| Stack smashing protection | Yes | Nightly |
-| Forward-edge control flow protection | Yes | Nightly |
-| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly |
+| Exploit mitigation | Supported | Enabled by default | Since |
+| - | - | - | - |
+| Position-independent executable | Yes | Yes | 0.12.0 (2014-10-09) |
+| Integer overflow checks | Yes | (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) |
+| Non-executable memory regions | Yes | Yes | 1.8.0 (2016-04-14) |
+| Stack clashing protection | Yes | Yes | 1.20.0 (2017-08-31) |
+| Read-only relocations and immediate binding | Yes | Yes | 1.21.0 (2017-10-12) |
+| Heap corruption protection | Yes | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) |
+| Stack smashing protection | Yes | No, `-Z stack-protector` | Nightly |
+| Forward-edge control flow protection | Yes | No, `-Z sanitizer=cfi` | Nightly |
+| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | No, `-Z sanitizer=shadow-call-stack,safestack` | Nightly |
 
 [^all-targets]: See <https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
     for a list of targets and their default options.
diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md
index 994b3adb92e..8592ce7eda9 100644
--- a/src/doc/rustc/src/platform-support/xtensa.md
+++ b/src/doc/rustc/src/platform-support/xtensa.md
@@ -24,4 +24,4 @@ Xtensa targets that support `std` are documented in the [ESP-IDF platform suppor
 
 ## Building the targets
 
-The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html).
+The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of The Rust on ESP Book](https://docs.espressif.com/projects/rust/book/installation/index.html).
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 09647492d93..5ac5da24299 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1677,7 +1677,7 @@ impl Type {
         }
     }
 
-    pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
+    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
         match self {
             Type::Path { path, .. } => path.generics(),
             _ => None,
@@ -2227,7 +2227,7 @@ impl Path {
         self.segments.last().map(|seg| &seg.args)
     }
 
-    pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
+    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
         self.segments.last().and_then(|seg| {
             if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
                 Some(args.iter().filter_map(|arg| match arg {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index fd1b17b6476..813fdee57e1 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -343,13 +343,11 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
 pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
     match n.kind() {
         ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => {
-            let s = if let Some(def) = def.as_local() {
+            if let Some(def) = def.as_local() {
                 rendered_const(cx.tcx, cx.tcx.hir_body_owned_by(def), def)
             } else {
                 inline::print_inlined_const(cx.tcx, def)
-            };
-
-            s
+            }
         }
         // array lengths are obviously usize
         ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 9b4d2533954..38ba6b4503d 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -632,7 +632,7 @@ fn run_test(
         // the user to exploit nightly-only features on stable
         runner_compiler.env("RUSTC_BOOTSTRAP", "1");
         runner_compiler.args(compiler_args);
-        runner_compiler.args(&["--crate-type=bin", "-o"]).arg(&output_file);
+        runner_compiler.args(["--crate-type=bin", "-o"]).arg(&output_file);
         let mut extern_path = std::ffi::OsString::from(format!(
             "--extern=doctest_bundle_{edition}=",
             edition = doctest.edition
@@ -657,7 +657,7 @@ fn run_test(
         extern_path.push(&output_bundle_file);
         runner_compiler.arg(extern_path);
         runner_compiler.arg(&runner_input_file);
-        if std::fs::write(&runner_input_file, &merged_test_code).is_err() {
+        if std::fs::write(&runner_input_file, merged_test_code).is_err() {
             // If we cannot write this file for any reason, we leave. All combined tests will be
             // tested as standalone tests.
             return Err(TestFailure::CompileError);
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index 96975105ac5..f5ec828187a 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -140,7 +140,7 @@ impl HirCollector<'_> {
                 .iter()
                 .filter(|a| a.has_name(sym::attr))
                 .flat_map(|a| a.meta_item_list().unwrap_or_default())
-                .map(|i| pprust::meta_list_item_to_string(i))
+                .map(pprust::meta_list_item_to_string)
             {
                 // Add the additional attributes to the global_crate_attrs vector
                 self.collector.global_crate_attrs.push(attr);
diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs
index 79ff1fa38c3..aa4be4db997 100644
--- a/src/librustdoc/formats/renderer.rs
+++ b/src/librustdoc/formats/renderer.rs
@@ -81,7 +81,7 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>(
         let _timer =
             prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string());
 
-        cx.mod_item_in(&item)?;
+        cx.mod_item_in(item)?;
         let (clean::StrippedItem(box clean::ModuleItem(ref module))
         | clean::ModuleItem(ref module)) = item.inner.kind
         else {
@@ -99,7 +99,7 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>(
     } else if let Some(item_name) = item.name
         && !item.is_extern_crate()
     {
-        prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(&item))?;
+        prof.generic_activity_with_arg("render_item", item_name.as_str()).run(|| cx.item(item))?;
     }
     Ok(())
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index b16485107a0..be8a2d511e9 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -114,9 +114,9 @@ impl clean::Generics {
             let real_params =
                 fmt::from_fn(|f| real_params.clone().map(|g| g.print(cx)).joined(", ", f));
             if f.alternate() {
-                write!(f, "<{:#}>", real_params)
+                write!(f, "<{real_params:#}>")
             } else {
-                write!(f, "&lt;{}&gt;", real_params)
+                write!(f, "&lt;{real_params}&gt;")
             }
         })
     }
@@ -594,7 +594,7 @@ pub(crate) fn href_with_root_path(
             }
         }
     };
-    let url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote);
+    let url_parts = make_href(root_path, shortty, url_parts, fqp, is_remote);
     Ok((url_parts, shortty, fqp.clone()))
 }
 
@@ -1115,7 +1115,7 @@ impl clean::Impl {
                 {
                     let last = ty.last();
                     if f.alternate() {
-                        write!(f, "{}<", last)?;
+                        write!(f, "{last}<")?;
                         self.print_type(inner_type, f, use_absolute, cx)?;
                         write!(f, ">")?;
                     } else {
@@ -1219,7 +1219,7 @@ pub(crate) fn print_params(params: &[clean::Parameter], cx: &Context<'_>) -> imp
             .map(|param| {
                 fmt::from_fn(|f| {
                     if let Some(name) = param.name {
-                        write!(f, "{}: ", name)?;
+                        write!(f, "{name}: ")?;
                     }
                     param.type_.print(cx).fmt(f)
                 })
@@ -1341,7 +1341,7 @@ impl clean::FnDecl {
                     write!(f, "const ")?;
                 }
                 if let Some(name) = param.name {
-                    write!(f, "{}: ", name)?;
+                    write!(f, "{name}: ")?;
                 }
                 param.type_.print(cx).fmt(f)?;
             }
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index b2feee36c93..272180fb990 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -547,7 +547,7 @@ impl<'a> Iterator for TokenIter<'a> {
 fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> {
     let ignore: &[&str] =
         if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
-    if ignore.iter().any(|k| *k == text) {
+    if ignore.contains(&text) {
         return None;
     }
     Some(match text {
@@ -1159,7 +1159,7 @@ fn string_without_closing_tag<T: Display>(
         return Some("</a>");
     }
     if !open_tag {
-        write!(out, "{}", text_s).unwrap();
+        out.write_str(&text_s).unwrap();
         return None;
     }
     let klass_s = klass.as_html();
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 50320cb231d..1f92c521d46 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -132,6 +132,5 @@ pub(crate) fn redirect(url: &str) -> String {
     <script>location.replace("{url}" + location.search + location.hash);</script>
 </body>
 </html>"##,
-        url = url,
     )
 }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index e41435de29c..4addf2c3c96 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -251,7 +251,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
                     if !parse_result.rust {
                         let added_classes = parse_result.added_classes;
                         let lang_string = if let Some(lang) = parse_result.unknown.first() {
-                            format!("language-{}", lang)
+                            format!("language-{lang}")
                         } else {
                             String::new()
                         };
@@ -999,7 +999,7 @@ impl<'a, 'tcx> TagIterator<'a, 'tcx> {
 
         if let Some((_, c)) = self.inner.next() {
             if c != '=' {
-                self.emit_error(format!("expected `=`, found `{}`", c));
+                self.emit_error(format!("expected `=`, found `{c}`"));
                 return None;
             }
         } else {
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 7b814701a73..5ceb1fc988d 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -193,14 +193,12 @@ impl<'tcx> Context<'tcx> {
         if it.is_stripped()
             && let Some(def_id) = it.def_id()
             && def_id.is_local()
+            && (self.info.is_inside_inlined_module
+                || self.shared.cache.inlined_items.contains(&def_id))
         {
-            if self.info.is_inside_inlined_module
-                || self.shared.cache.inlined_items.contains(&def_id)
-            {
-                // For now we're forced to generate a redirect page for stripped items until
-                // `record_extern_fqn` correctly points to external items.
-                render_redirect_pages = true;
-            }
+            // For now we're forced to generate a redirect page for stripped items until
+            // `record_extern_fqn` correctly points to external items.
+            render_redirect_pages = true;
         }
         let mut title = String::new();
         if !is_module {
@@ -254,40 +252,36 @@ impl<'tcx> Context<'tcx> {
                 &self.shared.style_files,
             )
         } else {
-            if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id()) {
-                if self.current.len() + 1 != names.len()
-                    || self.current.iter().zip(names.iter()).any(|(a, b)| a != b)
-                {
-                    // We checked that the redirection isn't pointing to the current file,
-                    // preventing an infinite redirection loop in the generated
-                    // documentation.
-
-                    let path = fmt::from_fn(|f| {
-                        for name in &names[..names.len() - 1] {
-                            write!(f, "{name}/")?;
-                        }
-                        write!(f, "{}", print_item_path(ty, names.last().unwrap().as_str()))
-                    });
-                    match self.shared.redirections {
-                        Some(ref redirections) => {
-                            let mut current_path = String::new();
-                            for name in &self.current {
-                                current_path.push_str(name.as_str());
-                                current_path.push('/');
-                            }
-                            let _ = write!(
-                                current_path,
-                                "{}",
-                                print_item_path(ty, names.last().unwrap().as_str())
-                            );
-                            redirections.borrow_mut().insert(current_path, path.to_string());
-                        }
-                        None => {
-                            return layout::redirect(&format!(
-                                "{root}{path}",
-                                root = self.root_path()
-                            ));
+            if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id())
+                && (self.current.len() + 1 != names.len()
+                    || self.current.iter().zip(names.iter()).any(|(a, b)| a != b))
+            {
+                // We checked that the redirection isn't pointing to the current file,
+                // preventing an infinite redirection loop in the generated
+                // documentation.
+
+                let path = fmt::from_fn(|f| {
+                    for name in &names[..names.len() - 1] {
+                        write!(f, "{name}/")?;
+                    }
+                    write!(f, "{}", print_item_path(ty, names.last().unwrap().as_str()))
+                });
+                match self.shared.redirections {
+                    Some(ref redirections) => {
+                        let mut current_path = String::new();
+                        for name in &self.current {
+                            current_path.push_str(name.as_str());
+                            current_path.push('/');
                         }
+                        let _ = write!(
+                            current_path,
+                            "{}",
+                            print_item_path(ty, names.last().unwrap().as_str())
+                        );
+                        redirections.borrow_mut().insert(current_path, path.to_string());
+                    }
+                    None => {
+                        return layout::redirect(&format!("{root}{path}", root = self.root_path()));
                     }
                 }
             }
@@ -762,11 +756,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         // Flush pending errors.
         self.shared.fs.close();
         let nb_errors = self.shared.errors.iter().map(|err| self.tcx().dcx().err(err)).count();
-        if nb_errors > 0 {
-            Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
-        } else {
-            Ok(())
-        }
+        if nb_errors > 0 { Err(Error::new(io::Error::other("I/O error"), "")) } else { Ok(()) }
     }
 
     fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> {
@@ -842,7 +832,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             self.info.render_redirect_pages = item.is_stripped();
         }
 
-        let buf = self.render_item(&item, false);
+        let buf = self.render_item(item, false);
         // buf will be empty if the item is stripped and there is no redirect for it
         if !buf.is_empty() {
             let name = item.name.as_ref().unwrap();
@@ -853,7 +843,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             self.shared.fs.write(joint_dst, buf)?;
 
             if !self.info.render_redirect_pages {
-                self.shared.all.borrow_mut().append(full_path(self, &item), &item_type);
+                self.shared.all.borrow_mut().append(full_path(self, item), &item_type);
             }
             // If the item is a macro, redirect from the old macro URL (with !)
             // to the new one (without).
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 2cfc9af39e4..872dbbcd19e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1483,10 +1483,10 @@ fn render_deref_methods(
             }
         }
         render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
-    } else if let Some(prim) = target.primitive_type() {
-        if let Some(&did) = cache.primitive_locations.get(&prim) {
-            render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
-        }
+    } else if let Some(prim) = target.primitive_type()
+        && let Some(&did) = cache.primitive_locations.get(&prim)
+    {
+        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
     }
 }
 
@@ -2058,21 +2058,20 @@ fn render_impl(
         // default items which weren't overridden in the implementation block.
         // We don't emit documentation for default items if they appear in the
         // Implementations on Foreign Types or Implementors sections.
-        if rendering_params.show_default_items {
-            if let Some(t) = trait_
-                && !impl_.is_negative_trait_impl()
-            {
-                render_default_items(
-                    &mut default_impl_items,
-                    &mut impl_items,
-                    cx,
-                    t,
-                    impl_,
-                    &i.impl_item,
-                    render_mode,
-                    rendering_params,
-                )?;
-            }
+        if rendering_params.show_default_items
+            && let Some(t) = trait_
+            && !impl_.is_negative_trait_impl()
+        {
+            render_default_items(
+                &mut default_impl_items,
+                &mut impl_items,
+                cx,
+                t,
+                impl_,
+                &i.impl_item,
+                render_mode,
+                rendering_params,
+            )?;
         }
         if render_mode == RenderMode::Normal {
             let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
@@ -2570,7 +2569,7 @@ fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec<String>
         match ty {
             clean::Type::Path { path } => process_path(path.def_id()),
             clean::Type::Tuple(tys) => {
-                work.extend(tys.into_iter());
+                work.extend(tys.iter());
             }
             clean::Type::Slice(ty) => {
                 work.push_back(ty);
diff --git a/src/librustdoc/html/render/ordered_json.rs b/src/librustdoc/html/render/ordered_json.rs
index d1dddfebc83..be51dad1c2b 100644
--- a/src/librustdoc/html/render/ordered_json.rs
+++ b/src/librustdoc/html/render/ordered_json.rs
@@ -25,7 +25,7 @@ impl OrderedJson {
             .into_iter()
             .sorted_unstable_by(|a, b| a.borrow().cmp(b.borrow()))
             .format_with(",", |item, f| f(item.borrow()));
-        Self(format!("[{}]", items))
+        Self(format!("[{items}]"))
     }
 
     pub(crate) fn array_unsorted<T: Borrow<Self>, I: IntoIterator<Item = T>>(items: I) -> Self {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 5fbda4797cc..02ee34aaac6 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1451,7 +1451,7 @@ item_template!(
 
 impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
     fn render_union(&self) -> impl Display {
-        render_union(self.it, Some(&self.generics), &self.fields, self.cx)
+        render_union(self.it, Some(self.generics), self.fields, self.cx)
     }
 
     fn document_field(&self, field: &'a clean::Item) -> impl Display {
@@ -1982,16 +1982,14 @@ fn item_constant(
                 w.write_str(";")?;
             }
 
-            if !is_literal {
-                if let Some(value) = &value {
-                    let value_lowercase = value.to_lowercase();
-                    let expr_lowercase = expr.to_lowercase();
+            if !is_literal && let Some(value) = &value {
+                let value_lowercase = value.to_lowercase();
+                let expr_lowercase = expr.to_lowercase();
 
-                    if value_lowercase != expr_lowercase
-                        && value_lowercase.trim_end_matches("i32") != expr_lowercase
-                    {
-                        write!(w, " // {value}", value = Escape(value))?;
-                    }
+                if value_lowercase != expr_lowercase
+                    && value_lowercase.trim_end_matches("i32") != expr_lowercase
+                {
+                    write!(w, " // {value}", value = Escape(value))?;
                 }
             }
             Ok::<(), fmt::Error>(())
@@ -2071,41 +2069,39 @@ fn item_fields(
                 _ => None,
             })
             .peekable();
-        if let None | Some(CtorKind::Fn) = ctor_kind {
-            if fields.peek().is_some() {
-                let title = format!(
-                    "{}{}",
-                    if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
-                    document_non_exhaustive_header(it),
-                );
+        if let None | Some(CtorKind::Fn) = ctor_kind
+            && fields.peek().is_some()
+        {
+            let title = format!(
+                "{}{}",
+                if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
+                document_non_exhaustive_header(it),
+            );
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    &title,
+                    "fields",
+                    Some("fields"),
+                    document_non_exhaustive(it)
+                )
+            )?;
+            for (index, (field, ty)) in fields.enumerate() {
+                let field_name =
+                    field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
+                let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
                 write!(
                     w,
-                    "{}",
-                    write_section_heading(
-                        &title,
-                        "fields",
-                        Some("fields"),
-                        document_non_exhaustive(it)
-                    )
+                    "<span id=\"{id}\" class=\"{item_type} section-header\">\
+                        <a href=\"#{id}\" class=\"anchor field\">§</a>\
+                        <code>{field_name}: {ty}</code>\
+                    </span>\
+                    {doc}",
+                    item_type = ItemType::StructField,
+                    ty = ty.print(cx),
+                    doc = document(cx, field, Some(it), HeadingOffset::H3),
                 )?;
-                for (index, (field, ty)) in fields.enumerate() {
-                    let field_name = field
-                        .name
-                        .map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
-                    let id =
-                        cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
-                    write!(
-                        w,
-                        "<span id=\"{id}\" class=\"{item_type} section-header\">\
-                            <a href=\"#{id}\" class=\"anchor field\">§</a>\
-                            <code>{field_name}: {ty}</code>\
-                        </span>\
-                        {doc}",
-                        item_type = ItemType::StructField,
-                        ty = ty.print(cx),
-                        doc = document(cx, field, Some(it), HeadingOffset::H3),
-                    )?;
-                }
             }
         }
         Ok(())
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 91540e06e33..b9f5ada417c 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -541,7 +541,7 @@ fn sidebar_deref_methods<'a>(
                 .iter()
                 .filter(|i| {
                     i.inner_impl().trait_.is_none()
-                        && real_target.is_doc_subtype_of(&i.inner_impl().for_, &c)
+                        && real_target.is_doc_subtype_of(&i.inner_impl().for_, c)
                 })
                 .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx()))
                 .collect::<Vec<_>>();
diff --git a/src/librustdoc/html/render/sorted_template.rs b/src/librustdoc/html/render/sorted_template.rs
index a7b954ab70b..659c5e6093b 100644
--- a/src/librustdoc/html/render/sorted_template.rs
+++ b/src/librustdoc/html/render/sorted_template.rs
@@ -63,7 +63,8 @@ impl<F: FileFormat> fmt::Display for SortedTemplate<F> {
         for (p, fragment) in self.fragments.iter().with_position() {
             let mut f = DeltaWriter { inner: &mut f, delta: 0 };
             let sep = if matches!(p, Position::First | Position::Only) { "" } else { F::SEPARATOR };
-            write!(f, "{}{}", sep, fragment)?;
+            f.write_str(sep)?;
+            f.write_str(fragment)?;
             fragment_lengths.push(f.delta);
         }
         let offset = Offset { start: self.before.len(), fragment_lengths };
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 0a84d8caa30..08bc0bb1950 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -50,7 +50,7 @@ impl JsonRenderer<'_> {
         let span = item.span(self.tcx);
         let visibility = item.visibility(self.tcx);
         let clean::ItemInner { name, item_id, .. } = *item.inner;
-        let id = self.id_from_item(&item);
+        let id = self.id_from_item(item);
         let inner = match item.kind {
             clean::KeywordItem => return None,
             clean::StrippedItem(ref inner) => {
@@ -86,14 +86,14 @@ impl JsonRenderer<'_> {
         items
             .iter()
             .filter(|i| !i.is_stripped() && !i.is_keyword())
-            .map(|i| self.id_from_item(&i))
+            .map(|i| self.id_from_item(i))
             .collect()
     }
 
     fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec<Option<Id>> {
         items
             .iter()
-            .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(&i)))
+            .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(i)))
             .collect()
     }
 }
@@ -358,12 +358,12 @@ impl FromClean<clean::Struct> for Struct {
         let clean::Struct { ctor_kind, generics, fields } = struct_;
 
         let kind = match ctor_kind {
-            Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(&fields)),
+            Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(fields)),
             Some(CtorKind::Const) => {
                 assert!(fields.is_empty());
                 StructKind::Unit
             }
-            None => StructKind::Plain { fields: renderer.ids(&fields), has_stripped_fields },
+            None => StructKind::Plain { fields: renderer.ids(fields), has_stripped_fields },
         };
 
         Struct {
@@ -381,7 +381,7 @@ impl FromClean<clean::Union> for Union {
         Union {
             generics: generics.into_json(renderer),
             has_stripped_fields,
-            fields: renderer.ids(&fields),
+            fields: renderer.ids(fields),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -659,7 +659,7 @@ impl FromClean<clean::FnDecl> for FunctionSignature {
         let clean::FnDecl { inputs, output, c_variadic } = decl;
         FunctionSignature {
             inputs: inputs
-                .into_iter()
+                .iter()
                 .map(|param| {
                     // `_` is the most sensible name for missing param names.
                     let name = param.name.unwrap_or(kw::Underscore).to_string();
@@ -684,7 +684,7 @@ impl FromClean<clean::Trait> for Trait {
             is_auto,
             is_unsafe,
             is_dyn_compatible,
-            items: renderer.ids(&items),
+            items: renderer.ids(items),
             generics: generics.into_json(renderer),
             bounds: bounds.into_json(renderer),
             implementations: Vec::new(), // Added in JsonRenderer::item
@@ -727,7 +727,7 @@ impl FromClean<clean::Impl> for Impl {
                 .collect(),
             trait_: trait_.into_json(renderer),
             for_: for_.into_json(renderer),
-            items: renderer.ids(&items),
+            items: renderer.ids(items),
             is_negative,
             is_synthetic,
             blanket_impl: blanket_impl.map(|x| x.into_json(renderer)),
@@ -770,7 +770,7 @@ impl FromClean<clean::Variant> for Variant {
 
         let kind = match &variant.kind {
             CLike => VariantKind::Plain,
-            Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(&fields)),
+            Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(fields)),
             Struct(s) => VariantKind::Struct {
                 has_stripped_fields: s.has_stripped_entries(),
                 fields: renderer.ids(&s.fields),
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 600a4b429f3..760e48baffa 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -133,7 +133,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
     let feature_stability: FxHashMap<&str, Stability> = sess
         .target
         .rust_target_features()
-        .into_iter()
+        .iter()
         .copied()
         .map(|(name, stability, _)| (name, stability))
         .collect();
@@ -143,7 +143,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
         target_features: sess
             .target
             .rust_target_features()
-            .into_iter()
+            .iter()
             .copied()
             .filter(|(_, stability, _)| {
                 // Describe only target features which the user can toggle
@@ -157,7 +157,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
                         _ => None,
                     },
                     implies_features: implied_features
-                        .into_iter()
+                        .iter()
                         .copied()
                         .filter(|name| {
                             // Imply only target features which the user can toggle
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index ca6f67eb6df..5a9aa2a94c8 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -274,7 +274,7 @@ impl From<DiagnosticInfo<'_>> for OwnedDiagnosticInfo {
 }
 
 impl OwnedDiagnosticInfo {
-    pub(crate) fn into_info(&self) -> DiagnosticInfo<'_> {
+    pub(crate) fn as_info(&self) -> DiagnosticInfo<'_> {
         DiagnosticInfo {
             item: &self.item,
             ori_link: &self.ori_link,
@@ -1177,7 +1177,7 @@ impl LinkCollector<'_, '_> {
                     // Primitive types are always valid.
                     Res::Primitive(_) => true,
                 });
-                let diag_info = info.diag_info.into_info();
+                let diag_info = info.diag_info.as_info();
                 match info.resolved.len() {
                     1 => {
                         let (res, fragment) = info.resolved.pop().unwrap();
@@ -1243,17 +1243,16 @@ impl LinkCollector<'_, '_> {
             disambiguator,
             None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
         ) && !matches!(res, Res::Primitive(_))
+            && let Some(prim) = resolve_primitive(path_str, TypeNS)
         {
-            if let Some(prim) = resolve_primitive(path_str, TypeNS) {
-                // `prim@char`
-                if matches!(disambiguator, Some(Disambiguator::Primitive)) {
-                    res = prim;
-                } else {
-                    // `[char]` when a `char` module is in scope
-                    let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)];
-                    ambiguity_error(self.cx, &diag_info, path_str, candidates, true);
-                    return None;
-                }
+            // `prim@char`
+            if matches!(disambiguator, Some(Disambiguator::Primitive)) {
+                res = prim;
+            } else {
+                // `[char]` when a `char` module is in scope
+                let candidates = &[(res, res.def_id(self.cx.tcx)), (prim, None)];
+                ambiguity_error(self.cx, &diag_info, path_str, candidates, true);
+                return None;
             }
         }
 
@@ -2233,7 +2232,7 @@ fn ambiguity_error(
     // proc macro can exist in multiple namespaces at once, so we need to compare `DefIds`
     //  to remove the candidate in the fn namespace.
     let mut possible_proc_macro_id = None;
-    let is_proc_macro_crate = cx.tcx.crate_types() == &[CrateType::ProcMacro];
+    let is_proc_macro_crate = cx.tcx.crate_types() == [CrateType::ProcMacro];
     let mut kinds = candidates
         .iter()
         .map(|(res, def_id)| {
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index 5757b6a9740..e69cf87f957 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -93,14 +93,14 @@ fn check_redundant_explicit_link<'md>(
         if let Event::Start(Tag::Link { link_type, dest_url, .. }) = event {
             let link_data = collect_link_data(&mut offset_iter);
 
-            if let Some(resolvable_link) = link_data.resolvable_link.as_ref() {
-                if &link_data.display_link.replace('`', "") != resolvable_link {
-                    // Skips if display link does not match to actual
-                    // resolvable link, usually happens if display link
-                    // has several segments, e.g.
-                    // [this is just an `Option`](Option)
-                    continue;
-                }
+            if let Some(resolvable_link) = link_data.resolvable_link.as_ref()
+                && &link_data.display_link.replace('`', "") != resolvable_link
+            {
+                // Skips if display link does not match to actual
+                // resolvable link, usually happens if display link
+                // has several segments, e.g.
+                // [this is just an `Option`](Option)
+                continue;
             }
 
             let explicit_link = dest_url.to_string();
diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs
index b53e3b4e3d7..bb13308e6c2 100644
--- a/src/librustdoc/passes/strip_aliased_non_local.rs
+++ b/src/librustdoc/passes/strip_aliased_non_local.rs
@@ -47,13 +47,11 @@ impl DocFolder for NonLocalStripper<'_> {
         // FIXME(#125009): Not-local should probably consider same Cargo workspace
         if let Some(def_id) = i.def_id()
             && !def_id.is_local()
-        {
-            if i.is_doc_hidden()
+            && (i.is_doc_hidden()
                 // Default to *not* stripping items with inherited visibility.
-                || i.visibility(self.tcx).is_some_and(|viz| viz != Visibility::Public)
-            {
-                return Some(strip_item(i));
-            }
+                || i.visibility(self.tcx).is_some_and(|viz| viz != Visibility::Public))
+        {
+            return Some(strip_item(i));
         }
 
         Some(self.fold_item_recur(i))
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 33da1a25db1..c83070aaba7 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -88,11 +88,37 @@ string_enum! {
     }
 }
 
+string_enum! {
+    #[derive(Clone, Copy, PartialEq, Debug, Hash)]
+    pub enum RunResult {
+        Pass => "run-pass",
+        Fail => "run-fail",
+        Crash => "run-crash",
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum RunFailMode {
+    /// Running the program must make it exit with a regular failure exit code
+    /// in the range `1..=127`. If the program is terminated by e.g. a signal
+    /// the test will fail.
+    Fail,
+    /// Running the program must result in a crash, e.g. by `SIGABRT` or
+    /// `SIGSEGV` on Unix or on Windows by having an appropriate NTSTATUS high
+    /// bit in the exit code.
+    Crash,
+    /// Running the program must either fail or crash. Useful for e.g. sanitizer
+    /// tests since some sanitizer implementations exit the process with code 1
+    /// to in the face of memory errors while others abort (crash) the process
+    /// in the face of memory errors.
+    FailOrCrash,
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
 pub enum FailMode {
     Check,
     Build,
-    Run,
+    Run(RunFailMode),
 }
 
 string_enum! {
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 93133ea0bfd..513716357f4 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf};
 use semver::Version;
 use tracing::*;
 
-use crate::common::{Config, Debugger, FailMode, PassMode, TestMode};
+use crate::common::{Config, Debugger, FailMode, PassMode, RunFailMode, TestMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
 use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
 use crate::directives::needs::CachedNeedsConditions;
@@ -654,7 +654,13 @@ impl TestProps {
             Some(FailMode::Build)
         } else if config.parse_name_directive(ln, "run-fail") {
             check_ui("run");
-            Some(FailMode::Run)
+            Some(FailMode::Run(RunFailMode::Fail))
+        } else if config.parse_name_directive(ln, "run-crash") {
+            check_ui("run");
+            Some(FailMode::Run(RunFailMode::Crash))
+        } else if config.parse_name_directive(ln, "run-fail-or-crash") {
+            check_ui("run");
+            Some(FailMode::Run(RunFailMode::FailOrCrash))
         } else {
             None
         };
@@ -1007,7 +1013,9 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "regex-error-pattern",
     "remap-src-base",
     "revisions",
+    "run-crash",
     "run-fail",
+    "run-fail-or-crash",
     "run-flags",
     "run-pass",
     "run-rustfix",
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index cb8f593c9df..f66d4f98f1f 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -16,8 +16,8 @@ use regex::{Captures, Regex};
 use tracing::*;
 
 use crate::common::{
-    CompareMode, Config, Debugger, FailMode, PassMode, TestMode, TestPaths, TestSuite,
-    UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG,
+    CompareMode, Config, Debugger, FailMode, PassMode, RunFailMode, RunResult, TestMode, TestPaths,
+    TestSuite, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG,
     UI_WINDOWS_SVG, expected_output_path, incremental_dir, output_base_dir, output_base_name,
     output_testname_unique,
 };
@@ -282,7 +282,8 @@ impl<'test> TestCx<'test> {
     fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
         let test_should_run = match self.config.mode {
             TestMode::Ui
-                if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) =>
+                if pm == Some(PassMode::Run)
+                    || matches!(self.props.fail_mode, Some(FailMode::Run(_))) =>
             {
                 true
             }
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index f6bc85cd051..0507c2600ae 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json};
 use tracing::debug;
 
 use super::{
-    AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput,
-    Truncated, UI_FIXED, WillExecute,
+    AllowUnused, Emit, FailMode, LinkToAux, PassMode, RunFailMode, RunResult, TargetLocation,
+    TestCx, TestOutput, Truncated, UI_FIXED, WillExecute,
 };
 use crate::json;
 
@@ -140,12 +140,53 @@ impl TestCx<'_> {
                     &proc_res,
                 );
             }
+            let code = proc_res.status.code();
+            let run_result = if proc_res.status.success() {
+                RunResult::Pass
+            } else if code.is_some_and(|c| c >= 1 && c <= 127) {
+                RunResult::Fail
+            } else {
+                RunResult::Crash
+            };
+            // Help users understand why the test failed by including the actual
+            // exit code and actual run result in the failure message.
+            let pass_hint = format!("code={code:?} so test would pass with `{run_result}`");
             if self.should_run_successfully(pm) {
-                if !proc_res.status.success() {
-                    self.fatal_proc_rec("test run failed!", &proc_res);
+                if run_result != RunResult::Pass {
+                    self.fatal_proc_rec(
+                        &format!("test did not exit with success! {pass_hint}"),
+                        &proc_res,
+                    );
+                }
+            } else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Fail)) {
+                // If the test is marked as `run-fail` but do not support
+                // unwinding we allow it to crash, since a panic will trigger an
+                // abort (crash) instead of unwind (exit with code 101).
+                let crash_ok = !self.config.can_unwind();
+                if run_result != RunResult::Fail && !(crash_ok && run_result == RunResult::Crash) {
+                    let err = if crash_ok {
+                        format!(
+                            "test did not exit with failure or crash (`{}` can't unwind)! {pass_hint}",
+                            self.config.target
+                        )
+                    } else {
+                        format!("test did not exit with failure! {pass_hint}")
+                    };
+                    self.fatal_proc_rec(&err, &proc_res);
                 }
-            } else if proc_res.status.success() {
-                self.fatal_proc_rec("test run succeeded!", &proc_res);
+            } else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Crash)) {
+                if run_result != RunResult::Crash {
+                    self.fatal_proc_rec(&format!("test did not crash! {pass_hint}"), &proc_res);
+                }
+            } else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::FailOrCrash)) {
+                if run_result != RunResult::Fail && run_result != RunResult::Crash {
+                    self.fatal_proc_rec(
+                        &format!("test did not exit with failure or crash! {pass_hint}"),
+                        &proc_res,
+                    );
+                }
+            } else {
+                unreachable!("run_ui_test() must not be called if the test should not run");
             }
 
             self.get_output(&proc_res)
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 601acc00bd6..d734ec333a5 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-ebd8557637b33cc09b6ee8273f3154d5d3af6a15
+6707bf0f59485cf054ac1095725df43220e4be20
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs
index 047fe07df14..5778765589d 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs
@@ -1,4 +1,6 @@
 //@ignore-target: windows # No pthreads on Windows
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
 
 /// Test that destroying a pthread_cond twice fails, even without a check for number validity
 
@@ -15,6 +17,6 @@ fn main() {
         libc::pthread_cond_destroy(cond.as_mut_ptr());
 
         libc::pthread_cond_destroy(cond.as_mut_ptr());
-        //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+        //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr
index 7abdfa87f75..6156070cf95 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC
    |
 LL |         libc::pthread_cond_destroy(cond.as_mut_ptr());
@@ -9,6 +9,9 @@ LL |         libc::pthread_cond_destroy(cond.as_mut_ptr());
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs
index 90e33d58673..91169660491 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs
@@ -1,5 +1,7 @@
 //@ignore-target: windows # No pthreads on Windows
 //@ignore-target: apple # Our macOS condattr don't have any fields so we do not notice this.
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
 
 /// Test that destroying a pthread_condattr twice fails, even without a check for number validity
 
@@ -13,6 +15,6 @@ fn main() {
         libc::pthread_condattr_destroy(attr.as_mut_ptr());
 
         libc::pthread_condattr_destroy(attr.as_mut_ptr());
-        //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+        //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr
index 28a66253ae8..da64970ff2e 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC
    |
 LL |         libc::pthread_condattr_destroy(attr.as_mut_ptr());
@@ -9,6 +9,9 @@ LL |         libc::pthread_condattr_destroy(attr.as_mut_ptr());
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs
index 1792c227e13..f04fe8be6b3 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs
@@ -1,4 +1,6 @@
 //@ignore-target: windows # No pthreads on Windows
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
 
 /// Test that destroying a pthread_mutex twice fails, even without a check for number validity
 
@@ -16,6 +18,6 @@ fn main() {
         libc::pthread_mutex_destroy(mutex.as_mut_ptr());
 
         libc::pthread_mutex_destroy(mutex.as_mut_ptr());
-        //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+        //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr
index e7a6dee0203..05db823b252 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC
    |
 LL |         libc::pthread_mutex_destroy(mutex.as_mut_ptr());
@@ -9,6 +9,9 @@ LL |         libc::pthread_mutex_destroy(mutex.as_mut_ptr());
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs
index 3711c1f8dc1..d9daf5259bb 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs
@@ -1,4 +1,6 @@
 //@ignore-target: windows # No pthreads on Windows
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
 
 /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity
 
@@ -12,6 +14,6 @@ fn main() {
         libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
 
         libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
-        //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+        //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr
index 0c9ee71de45..ee3883de36b 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC
    |
 LL |         libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
@@ -9,6 +9,9 @@ LL |         libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs
index 6a31e972e68..720ba71d238 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs
@@ -1,4 +1,6 @@
 //@ignore-target: windows # No pthreads on Windows
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
 
 /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity
 
@@ -9,6 +11,6 @@ fn main() {
         libc::pthread_rwlock_destroy(&mut lock);
 
         libc::pthread_rwlock_destroy(&mut lock);
-        //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+        //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr
index 836f0d060bd..430398dc8fd 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC
    |
 LL |         libc::pthread_rwlock_destroy(&mut lock);
@@ -9,6 +9,9 @@ LL |         libc::pthread_rwlock_destroy(&mut lock);
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr
index 6a7d9a495f9..3252368ea6d 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC
    |
 LL |             _observe = non_copy.0;
@@ -9,6 +9,11 @@ LL |             _observe = non_copy.0;
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
+ALLOC (stack variable, size: 4, align: 4) {
+    __ __ __ __                                     │ ░░░░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr
index 0fc634bb7fc..09a5b9a6496 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
    |
 LL |     unsafe { ptr.read() };
@@ -14,6 +14,11 @@ note: inside `main`
 LL |             Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
+ALLOC (stack variable, size: 4, align: 4) {
+    __ __ __ __                                     │ ░░░░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr
index 746ab2e59ca..24091547258 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
 LL |     unsafe { ptr.read() };
@@ -14,6 +14,11 @@ note: inside `main`
 LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
+ALLOC (stack variable, size: 4, align: 4) {
+    __ __ __ __                                     │ ░░░░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr
index 7747a75d1cf..93720ca7d27 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr
@@ -3,7 +3,7 @@ thread 'main' panicked at tests/fail/function_calls/return_pointer_on_unwind.rs:
 explicit panic
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC
    |
 LL |     dbg!(x.0);
@@ -15,6 +15,19 @@ LL |     dbg!(x.0);
    = note: inside `main` at RUSTLIB/std/src/macros.rs:LL:CC
    = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
+ALLOC (stack variable, size: 132, align: 4) {
+    0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x30 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x40 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x50 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x60 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x70 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░
+    0x80 │ __ __ __ __                                     │ ░░░░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs
index 0c305eed6e1..c03e468cfba 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs
@@ -1,4 +1,7 @@
 //@compile-flags: -Zmiri-disable-validation
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 #![feature(core_intrinsics, custom_mir)]
 use std::intrinsics::mir::*;
 
@@ -9,7 +12,7 @@ use std::intrinsics::mir::*;
 pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
     mir! {
         {
-            RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
+            RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .* but memory is uninitialized/
             Return()
         }
     }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr
index 1c22876ba43..1e7f500edb2 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC
    |
 LL |             RET = PtrMetadata(*p);
@@ -14,6 +14,9 @@ note: inside `main`
 LL |         let _meta = deref_meta(p.as_ptr().cast());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs
index a2ffdc92c4e..7053c0f6e18 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs
@@ -1,4 +1,7 @@
 //@compile-flags: -Zmiri-disable-validation
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]+..0x[0-9a-z]+\]" -> "[0xX..0xY]"
+
 #![feature(core_intrinsics, custom_mir)]
 use std::intrinsics::mir::*;
 
@@ -9,7 +12,7 @@ use std::intrinsics::mir::*;
 pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
     mir! {
         {
-            RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
+            RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .* but memory is uninitialized/
             Return()
         }
     }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
index 00e63b1275f..80b4c8bec0d 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
@@ -12,7 +12,7 @@ LL |         (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC
 
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC
    |
 LL |             RET = PtrMetadata(*p);
@@ -28,6 +28,9 @@ note: inside `main`
 LL |         let _meta = deref_meta(p.as_ptr().cast());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error; 1 warning emitted
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs
index e5a51289a8a..3ba29847337 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs
@@ -1,4 +1,7 @@
 //@compile-flags: -Zmiri-disable-validation
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 #![feature(core_intrinsics, custom_mir)]
 use std::intrinsics::mir::*;
 
@@ -9,7 +12,7 @@ use std::intrinsics::mir::*;
 pub unsafe fn deref_meta(p: *const *const i32) -> () {
     mir! {
         {
-            RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
+            RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/
             Return()
         }
     }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr
index 24066953d79..7a1f3d6ea84 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC
    |
 LL |             RET = PtrMetadata(*p);
@@ -14,6 +14,9 @@ note: inside `main`
 LL |         let _meta = deref_meta(p.as_ptr());
    |                     ^^^^^^^^^^^^^^^^^^^^^^
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.rs b/src/tools/miri/tests/fail/read_from_trivial_switch.rs
index d34b1cd5820..2696c42aeae 100644
--- a/src/tools/miri/tests/fail/read_from_trivial_switch.rs
+++ b/src/tools/miri/tests/fail/read_from_trivial_switch.rs
@@ -4,11 +4,14 @@
 //
 // See <https://github.com/rust-lang/miri/issues/4237>.
 
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 use std::mem::MaybeUninit;
 
 fn main() {
     let uninit: MaybeUninit<i32> = MaybeUninit::uninit();
     let bad_ref: &i32 = unsafe { uninit.assume_init_ref() };
     let &(0 | _) = bad_ref;
-    //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+    //~^ ERROR: /Undefined Behavior: .*, but memory is uninitialized .* requires initialized memory/
 }
diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr
index 923d836ee0c..1dcc341b7e6 100644
--- a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr
+++ b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/read_from_trivial_switch.rs:LL:CC
    |
 LL |     let &(0 | _) = bad_ref;
@@ -9,6 +9,9 @@ LL |     let &(0 | _) = bad_ref;
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/read_from_trivial_switch.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.rs b/src/tools/miri/tests/fail/uninit/padding-enum.rs
index e1a16bea23c..606fa21016f 100644
--- a/src/tools/miri/tests/fail/uninit/padding-enum.rs
+++ b/src/tools/miri/tests/fail/uninit/padding-enum.rs
@@ -1,3 +1,6 @@
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 use std::mem;
 
 // We have three fields to avoid the ScalarPair optimization.
diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.stderr b/src/tools/miri/tests/fail/uninit/padding-enum.stderr
index a9a5568f4e8..64229ac8817 100644
--- a/src/tools/miri/tests/fail/uninit/padding-enum.stderr
+++ b/src/tools/miri/tests/fail/uninit/padding-enum.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/uninit/padding-enum.rs:LL:CC
    |
 LL |         let _val = *c.add(padding_offset);
@@ -9,6 +9,9 @@ LL |         let _val = *c.add(padding_offset);
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/uninit/padding-enum.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.rs b/src/tools/miri/tests/fail/uninit/padding-pair.rs
index c8c00b3c65a..70ae48ff77d 100644
--- a/src/tools/miri/tests/fail/uninit/padding-pair.rs
+++ b/src/tools/miri/tests/fail/uninit/padding-pair.rs
@@ -1,3 +1,6 @@
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 #![feature(core_intrinsics)]
 
 use std::mem::{self, MaybeUninit};
diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.stderr b/src/tools/miri/tests/fail/uninit/padding-pair.stderr
index d281a351d41..2e7a577f204 100644
--- a/src/tools/miri/tests/fail/uninit/padding-pair.stderr
+++ b/src/tools/miri/tests/fail/uninit/padding-pair.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/uninit/padding-pair.rs:LL:CC
    |
 LL |     let v = unsafe { *z.offset(first_undef) };
@@ -9,6 +9,9 @@ LL |     let v = unsafe { *z.offset(first_undef) };
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/uninit/padding-pair.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/uninit/padding-struct.stderr b/src/tools/miri/tests/fail/uninit/padding-struct.stderr
index 3298f6a4510..05d754625d3 100644
--- a/src/tools/miri/tests/fail/uninit/padding-struct.stderr
+++ b/src/tools/miri/tests/fail/uninit/padding-struct.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x1..0x2], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
   --> tests/fail/uninit/padding-struct.rs:LL:CC
    |
 LL |         let _val = *c.add(1);
@@ -9,6 +9,11 @@ LL |         let _val = *c.add(1);
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/uninit/padding-struct.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0x1..0x2], in this allocation:
+ALLOC (stack variable, size: 4, align: 2) {
+    00 __ 00 00                                     │ .░..
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs
index 4e363dbf81e..549785e0223 100644
--- a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs
+++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.rs
@@ -1,3 +1,6 @@
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 use std::mem;
 
 // If this is `None`, the metadata becomes padding.
diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr
index d92d05ae631..ce11320ca1b 100644
--- a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr
+++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/uninit/padding-wide-ptr.rs:LL:CC
    |
 LL |         let _val = *c.add(mem::size_of::<*const u8>());
@@ -9,6 +9,9 @@ LL |         let _val = *c.add(mem::size_of::<*const u8>());
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/uninit/padding-wide-ptr.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs
index 0ba5520a544..c1d284c7057 100644
--- a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs
+++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.rs
@@ -1,3 +1,6 @@
+//@ normalize-stderr-test: "(\n)ALLOC \(.*\) \{\n(.*\n)*\}(\n)" -> "${1}ALLOC DUMP${3}"
+//@ normalize-stderr-test: "\[0x[0-9a-z]..0x[0-9a-z]\]" -> "[0xX..0xY]"
+
 #![feature(core_intrinsics)]
 
 use std::mem::{self, MaybeUninit};
diff --git a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr
index 0ae0ce5de9c..eb049dd41ec 100644
--- a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr
+++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0xX..0xY], but memory is uninitialized at [0xX..0xY], and this operation requires initialized memory
   --> tests/fail/uninit/transmute-pair-uninit.rs:LL:CC
    |
 LL |     let v = unsafe { *z.offset(first_undef) };
@@ -9,6 +9,9 @@ LL |     let v = unsafe { *z.offset(first_undef) };
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/uninit/transmute-pair-uninit.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0xX..0xY], in this allocation:
+ALLOC DUMP
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr
index d2a5a2d3831..5a5aa12987c 100644
--- a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr
+++ b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x5..0x6], but memory is uninitialized at [0x5..0x6], and this operation requires initialized memory
   --> tests/fail/uninit/uninit_byte_read.rs:LL:CC
    |
 LL |     let undef = unsafe { *v.as_ptr().add(5) };
@@ -9,6 +9,11 @@ LL |     let undef = unsafe { *v.as_ptr().add(5) };
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/uninit/uninit_byte_read.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0x5..0x6], in this allocation:
+ALLOC (Rust heap, size: 10, align: 1) {
+    __ __ __ __ __ __ __ __ __ __                   │ ░░░░░░░░░░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr
index 6e24cadfc20..0b1915621b2 100644
--- a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr
+++ b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> tests/fail/validity/invalid_int_op.rs:LL:CC
    |
 LL |     let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() };
@@ -9,6 +9,11 @@ LL |     let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() }
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/validity/invalid_int_op.rs:LL:CC
 
+Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
+ALLOC (stack variable, size: 4, align: 4) {
+    __ __ __ __                                     │ ░░░░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs
index e267f82e215..7ab160773ff 100644
--- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs
+++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.rs
@@ -20,6 +20,6 @@ fn partial_init() {
         assert!(*slice_ptr == 0);
         assert!(*slice_ptr.offset(1) == 0);
         // Reading the third is UB!
-        let _val = *slice_ptr.offset(2); //~ ERROR: Undefined Behavior: using uninitialized data
+        let _val = *slice_ptr.offset(2); //~ ERROR: /Undefined Behavior: reading memory.*, but memory is uninitialized/
     }
 }
diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr
index 84fd913b5e5..74a599ede5c 100644
--- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr
+++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr
@@ -17,7 +17,7 @@ note: inside `main`
 LL |     partial_init();
    |     ^^^^^^^^^^^^^^
 
-error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+error: Undefined Behavior: reading memory at ALLOC[0x2..0x3], but memory is uninitialized at [0x2..0x3], and this operation requires initialized memory
   --> tests/native-lib/fail/tracing/partial_init.rs:LL:CC
    |
 LL |         let _val = *slice_ptr.offset(2);
@@ -33,6 +33,11 @@ note: inside `main`
 LL |     partial_init();
    |     ^^^^^^^^^^^^^^
 
+Uninitialized memory occurred at ALLOC[0x2..0x3], in this allocation:
+ALLOC (stack variable, size: 3, align: 1) {
+    ╾00[wildcard] (1 ptr byte)╼ ╾00[wildcard] (1 ptr byte)╼ __                                        │ ━━░
+}
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
 error: aborting due to 1 previous error; 1 warning emitted
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
index e8957846ad5..9e9fadfca9e 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
@@ -336,7 +336,7 @@ fn test_nanosleep() {
     let remainder = ptr::null_mut::<libc::timespec>();
     let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) };
     assert_eq!(is_error, 0);
-    assert!(start_test_sleep.elapsed() < Duration::from_millis(10));
+    assert!(start_test_sleep.elapsed() < Duration::from_millis(100));
 
     let start_test_sleep = Instant::now();
     let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 };
@@ -390,7 +390,7 @@ mod test_clock_nanosleep {
             )
         };
         assert_eq!(error, 0);
-        assert!(start_test_sleep.elapsed() < Duration::from_millis(10));
+        assert!(start_test_sleep.elapsed() < Duration::from_millis(100));
 
         let start_test_sleep = Instant::now();
         let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC));
@@ -417,7 +417,7 @@ mod test_clock_nanosleep {
             libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder)
         };
         assert_eq!(error, 0);
-        assert!(start_test_sleep.elapsed() < Duration::from_millis(10));
+        assert!(start_test_sleep.elapsed() < Duration::from_millis(100));
 
         let start_test_sleep = Instant::now();
         let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 };
diff --git a/src/tools/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs
index 946e926a3c0..d41dc80e6b2 100644
--- a/src/tools/opt-dist/src/environment.rs
+++ b/src/tools/opt-dist/src/environment.rs
@@ -27,6 +27,7 @@ pub struct Environment {
     shared_llvm: bool,
     run_tests: bool,
     fast_try_build: bool,
+    build_llvm: bool,
 }
 
 impl Environment {
@@ -111,6 +112,10 @@ impl Environment {
     pub fn is_fast_try_build(&self) -> bool {
         self.fast_try_build
     }
+
+    pub fn build_llvm(&self) -> bool {
+        self.build_llvm
+    }
 }
 
 /// What is the extension of binary executables on this platform?
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 0dc6e56b9d5..56eff2ca2a7 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -139,8 +139,10 @@ impl Bootstrap {
         self
     }
 
-    pub fn llvm_pgo_optimize(mut self, profile: &LlvmPGOProfile) -> Self {
-        self.cmd = self.cmd.arg("--llvm-profile-use").arg(profile.0.as_str());
+    pub fn llvm_pgo_optimize(mut self, profile: Option<&LlvmPGOProfile>) -> Self {
+        if let Some(prof) = profile {
+            self.cmd = self.cmd.arg("--llvm-profile-use").arg(prof.0.as_str());
+        }
         self
     }
 
@@ -174,8 +176,10 @@ impl Bootstrap {
         self
     }
 
-    pub fn with_bolt_profile(mut self, profile: BoltProfile) -> Self {
-        self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str());
+    pub fn with_bolt_profile(mut self, profile: Option<BoltProfile>) -> Self {
+        if let Some(prof) = profile {
+            self.cmd = self.cmd.arg("--reproducible-artifact").arg(prof.0.as_str());
+        }
         self
     }
 
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index 9c8a6637a3b..7857f196626 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -98,6 +98,10 @@ enum EnvironmentCmd {
         /// Perform tests after final build if it's not a fast try build
         #[arg(long)]
         run_tests: bool,
+
+        /// Will be LLVM built during the run?
+        #[arg(long, default_value_t = true, action(clap::ArgAction::Set))]
+        build_llvm: bool,
     },
     /// Perform an optimized build on Linux CI, from inside Docker.
     LinuxCi {
@@ -133,6 +137,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
             benchmark_cargo_config,
             shared,
             run_tests,
+            build_llvm,
         } => {
             let env = EnvironmentBuilder::default()
                 .host_tuple(target_triple)
@@ -148,6 +153,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .benchmark_cargo_config(benchmark_cargo_config)
                 .run_tests(run_tests)
                 .fast_try_build(is_fast_try_build)
+                .build_llvm(build_llvm)
                 .build()?;
 
             (env, shared.build_args)
@@ -172,6 +178,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .skipped_tests(vec![])
                 .run_tests(true)
                 .fast_try_build(is_fast_try_build)
+                .build_llvm(true)
                 .build()?;
 
             (env, shared.build_args)
@@ -193,6 +200,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .skipped_tests(vec![])
                 .run_tests(true)
                 .fast_try_build(is_fast_try_build)
+                .build_llvm(true)
                 .build()?;
 
             (env, shared.build_args)
@@ -255,30 +263,35 @@ fn execute_pipeline(
     // Stage 2: Gather LLVM PGO profiles
     // Here we build a PGO instrumented LLVM, reusing the previously PGO optimized rustc.
     // Then we use the instrumented LLVM to gather LLVM PGO profiles.
-    let llvm_pgo_profile = timer.section("Stage 2 (LLVM PGO)", |stage| {
-        // Remove the previous, uninstrumented build of LLVM.
-        clear_llvm_files(env)?;
+    let llvm_pgo_profile = if env.build_llvm() {
+        timer.section("Stage 2 (LLVM PGO)", |stage| {
+            // Remove the previous, uninstrumented build of LLVM.
+            clear_llvm_files(env)?;
 
-        let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo");
+            let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo");
 
-        stage.section("Build PGO instrumented LLVM", |section| {
-            Bootstrap::build(env)
-                .llvm_pgo_instrument(&llvm_profile_dir_root)
-                .avoid_rustc_rebuild()
-                .run(section)
-        })?;
+            stage.section("Build PGO instrumented LLVM", |section| {
+                Bootstrap::build(env)
+                    .llvm_pgo_instrument(&llvm_profile_dir_root)
+                    .avoid_rustc_rebuild()
+                    .run(section)
+            })?;
 
-        let profile = stage
-            .section("Gather profiles", |_| gather_llvm_profiles(env, &llvm_profile_dir_root))?;
+            let profile = stage.section("Gather profiles", |_| {
+                gather_llvm_profiles(env, &llvm_profile_dir_root)
+            })?;
 
-        print_free_disk_space()?;
+            print_free_disk_space()?;
 
-        // Proactively delete the instrumented artifacts, to avoid using them by accident in
-        // follow-up stages.
-        clear_llvm_files(env)?;
+            // Proactively delete the instrumented artifacts, to avoid using them by accident in
+            // follow-up stages.
+            clear_llvm_files(env)?;
 
-        Ok(profile)
-    })?;
+            Ok(Some(profile))
+        })?
+    } else {
+        None
+    };
 
     let bolt_profiles = if env.use_bolt() {
         // Stage 3: Build BOLT instrumented LLVM
@@ -286,37 +299,43 @@ fn execute_pipeline(
         // Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build.
         // BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc,
         // therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused.
+        let libdir = env.build_artifacts().join("stage2").join("lib");
         timer.section("Stage 3 (BOLT)", |stage| {
-            stage.section("Build PGO optimized LLVM", |stage| {
-                Bootstrap::build(env)
-                    .with_llvm_bolt_ldflags()
-                    .llvm_pgo_optimize(&llvm_pgo_profile)
-                    .avoid_rustc_rebuild()
-                    .run(stage)
-            })?;
-
-            let libdir = env.build_artifacts().join("stage2").join("lib");
-            // The actual name will be something like libLLVM.so.18.1-rust-dev.
-            let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?;
-
-            log::info!("Optimizing {llvm_lib} with BOLT");
-
-            // FIXME(kobzol): try gather profiles together, at once for LLVM and rustc
-            // Instrument the libraries and gather profiles
-            let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| {
-                stage.section("Gather profiles", |_| {
-                    gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir)
-                })
-            })?;
-            print_free_disk_space()?;
-
-            // Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked
-            // from several places, and this specific path (`llvm_lib`) will *not* be packaged into
-            // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
-            // therefore it will actually optimize all the hard links, which means that the final
-            // packaged `libLLVM.so` file *will* be BOLT optimized.
-            bolt_optimize(&llvm_lib, &llvm_profile, env)
-                .context("Could not optimize LLVM with BOLT")?;
+            let llvm_profile = if env.build_llvm() {
+                stage.section("Build PGO optimized LLVM", |stage| {
+                    Bootstrap::build(env)
+                        .with_llvm_bolt_ldflags()
+                        .llvm_pgo_optimize(llvm_pgo_profile.as_ref())
+                        .avoid_rustc_rebuild()
+                        .run(stage)
+                })?;
+
+                // The actual name will be something like libLLVM.so.18.1-rust-dev.
+                let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?;
+
+                log::info!("Optimizing {llvm_lib} with BOLT");
+
+                // FIXME(kobzol): try gather profiles together, at once for LLVM and rustc
+                // Instrument the libraries and gather profiles
+                let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| {
+                    stage.section("Gather profiles", |_| {
+                        gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir)
+                    })
+                })?;
+                print_free_disk_space()?;
+
+                // Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked
+                // from several places, and this specific path (`llvm_lib`) will *not* be packaged into
+                // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
+                // therefore it will actually optimize all the hard links, which means that the final
+                // packaged `libLLVM.so` file *will* be BOLT optimized.
+                bolt_optimize(&llvm_lib, &llvm_profile, env)
+                    .context("Could not optimize LLVM with BOLT")?;
+
+                Some(llvm_profile)
+            } else {
+                None
+            };
 
             let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?;
 
@@ -334,15 +353,16 @@ fn execute_pipeline(
             bolt_optimize(&rustc_lib, &rustc_profile, env)
                 .context("Could not optimize rustc with BOLT")?;
 
-            // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
-            Ok(vec![llvm_profile, rustc_profile])
+            // LLVM is not being cleared here. Either we built it and we want to use the BOLT-optimized LLVM, or we
+            // didn't build it, so we don't want to remove it.
+            Ok(vec![llvm_profile, Some(rustc_profile)])
         })?
     } else {
         vec![]
     };
 
     let mut dist = Bootstrap::dist(env, &dist_args)
-        .llvm_pgo_optimize(&llvm_pgo_profile)
+        .llvm_pgo_optimize(llvm_pgo_profile.as_ref())
         .rustc_pgo_optimize(&rustc_pgo_profile)
         .avoid_rustc_rebuild();
 
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 36a7d6a7cba..ae062d5c60c 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -163,7 +163,9 @@ pub fn gather_rustc_profiles(
     let merged_profile = env.artifact_dir().join("rustc-pgo.profdata");
     log::info!("Merging Rustc PGO profiles to {merged_profile}");
 
-    merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Target)?;
+    let llvm_profdata = if env.build_llvm() { LlvmProfdata::Target } else { LlvmProfdata::Host };
+
+    merge_llvm_profiles(env, &merged_profile, profile_root, llvm_profdata)?;
     log_profile_stats("Rustc", &merged_profile, profile_root)?;
 
     // We don't need the individual .profraw files now that they have been merged
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index e83b47e1380..fb00b3a943f 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -331,11 +331,9 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
             continue;
         }
 
-        if in_feature_group {
-            if let Some(doc_comment) = line.strip_prefix("///") {
-                doc_comments.push(doc_comment.trim().to_string());
-                continue;
-            }
+        if in_feature_group && let Some(doc_comment) = line.strip_prefix("///") {
+            doc_comments.push(doc_comment.trim().to_string());
+            continue;
         }
 
         let mut parts = line.split(',');
@@ -465,19 +463,20 @@ fn get_and_check_lib_features(
     map_lib_features(base_src_path, &mut |res, file, line| match res {
         Ok((name, f)) => {
             let mut check_features = |f: &Feature, list: &Features, display: &str| {
-                if let Some(s) = list.get(name) {
-                    if f.tracking_issue != s.tracking_issue && f.level != Status::Accepted {
-                        tidy_error!(
-                            bad,
-                            "{}:{}: feature gate {} has inconsistent `issue`: \"{}\" mismatches the {} `issue` of \"{}\"",
-                            file.display(),
-                            line,
-                            name,
-                            f.tracking_issue_display(),
-                            display,
-                            s.tracking_issue_display(),
-                        );
-                    }
+                if let Some(s) = list.get(name)
+                    && f.tracking_issue != s.tracking_issue
+                    && f.level != Status::Accepted
+                {
+                    tidy_error!(
+                        bad,
+                        "{}:{}: feature gate {} has inconsistent `issue`: \"{}\" mismatches the {} `issue` of \"{}\"",
+                        file.display(),
+                        line,
+                        name,
+                        f.tracking_issue_display(),
+                        display,
+                        s.tracking_issue_display(),
+                    );
                 }
             };
             check_features(&f, lang_features, "corresponding lang feature");
diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs
index 85c1ef6166a..836b5699289 100644
--- a/src/tools/tidy/src/fluent_period.rs
+++ b/src/tools/tidy/src/fluent_period.rs
@@ -33,14 +33,14 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) {
                 continue;
             }
 
-            if let Some(pat) = &m.value {
-                if let Some(PatternElement::TextElement { value }) = pat.elements.last() {
-                    // We don't care about ellipses.
-                    if value.ends_with(".") && !value.ends_with("...") {
-                        let ll = find_line(contents, value);
-                        let name = m.id.name;
-                        tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period");
-                    }
+            if let Some(pat) = &m.value
+                && let Some(PatternElement::TextElement { value }) = pat.elements.last()
+            {
+                // We don't care about ellipses.
+                if value.ends_with(".") && !value.ends_with("...") {
+                    let ll = find_line(contents, value);
+                    let name = m.id.name;
+                    tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period");
                 }
             }
 
@@ -50,12 +50,13 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) {
                     continue;
                 }
 
-                if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() {
-                    if value.ends_with(".") && !value.ends_with("...") {
-                        let ll = find_line(contents, value);
-                        let name = attr.id.name;
-                        tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period");
-                    }
+                if let Some(PatternElement::TextElement { value }) = attr.value.elements.last()
+                    && value.ends_with(".")
+                    && !value.ends_with("...")
+                {
+                    let ll = find_line(contents, value);
+                    let name = attr.id.name;
+                    tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period");
                 }
             }
         }
diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs
index 12fafd9a7ff..909bf482ddf 100644
--- a/src/tools/tidy/src/fluent_used.rs
+++ b/src/tools/tidy/src/fluent_used.rs
@@ -12,7 +12,7 @@ fn filter_used_messages(
 ) {
     // we don't just check messages never appear in Rust files,
     // because messages can be used as parts of other fluent messages in Fluent files,
-    // so we do checking messages appear only once in all Rust and Fluent files.
+    // so we check messages appear only once in all Rust and Fluent files.
     let matches = static_regex!(r"\w+").find_iter(contents);
     for name in matches {
         if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index ade4055b5bd..cb875504e1e 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -13,8 +13,9 @@ use termcolor::WriteColor;
 
 macro_rules! static_regex {
     ($re:literal) => {{
-        static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
-        RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
+        static RE: ::std::sync::LazyLock<::regex::Regex> =
+            ::std::sync::LazyLock::new(|| ::regex::Regex::new($re).unwrap());
+        &*RE
     }};
 }
 
@@ -134,7 +135,7 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool {
         eprintln!("No base commit, assuming all files are modified");
         return true;
     };
-    match crate::git_diff(&base_commit, "--name-status") {
+    match crate::git_diff(base_commit, "--name-status") {
         Some(output) => {
             let modified_files = output.lines().filter_map(|ln| {
                 let (status, name) = ln
diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs
index 1efe71b1687..6119eb58383 100644
--- a/src/tools/tidy/src/mir_opt_tests.rs
+++ b/src/tools/tidy/src/mir_opt_tests.rs
@@ -55,22 +55,21 @@ fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) {
         .filter(|e| e.file_type().is_file())
     {
         let path = file.path();
-        if path.extension() == Some("rs".as_ref()) {
-            if let Some(name) = path.file_name().and_then(|s| s.to_str()) {
-                if name.contains('-') {
-                    if !bless {
-                        tidy_error!(
-                            bad,
-                            "mir-opt test files should not have dashes in them: {}",
-                            path.display()
-                        );
-                    } else {
-                        let new_name = name.replace('-', "_");
-                        let mut new_path = path.to_owned();
-                        new_path.set_file_name(new_name);
-                        let _ = std::fs::rename(path, new_path);
-                    }
-                }
+        if path.extension() == Some("rs".as_ref())
+            && let Some(name) = path.file_name().and_then(|s| s.to_str())
+            && name.contains('-')
+        {
+            if !bless {
+                tidy_error!(
+                    bad,
+                    "mir-opt test files should not have dashes in them: {}",
+                    path.display()
+                );
+            } else {
+                let new_name = name.replace('-', "_");
+                let mut new_path = path.to_owned();
+                new_path.set_file_name(new_name);
+                let _ = std::fs::rename(path, new_path);
             }
         }
     }
diff --git a/src/tools/tidy/src/rustdoc_templates.rs b/src/tools/tidy/src/rustdoc_templates.rs
index dca3e8d9d25..597290a6a9a 100644
--- a/src/tools/tidy/src/rustdoc_templates.rs
+++ b/src/tools/tidy/src/rustdoc_templates.rs
@@ -26,7 +26,7 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) {
                         None
                     // Then we check if this a comment tag.
                     } else if *tag != "{#" {
-                        return Some(false);
+                        Some(false)
                     // And finally we check if the comment is empty (ie, only there to strip
                     // extra whitespace characters).
                     } else if let Some(start_pos) = line.rfind(tag) {
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 8dde4618ce5..35ed61eacc7 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -417,10 +417,10 @@ pub fn check(path: &Path, bad: &mut bool) {
             return;
         }
         // Shell completions are automatically generated
-        if let Some(p) = file.parent() {
-            if p.ends_with(Path::new("src/etc/completions")) {
-                return;
-            }
+        if let Some(p) = file.parent()
+            && p.ends_with(Path::new("src/etc/completions"))
+        {
+            return;
         }
         let [
             mut skip_cr,
@@ -604,25 +604,25 @@ pub fn check(path: &Path, bad: &mut bool) {
                         backtick_count += comment_text.chars().filter(|ch| *ch == '`').count();
                     }
                     comment_block = Some((start_line, backtick_count));
-                } else if let Some((start_line, backtick_count)) = comment_block.take() {
-                    if backtick_count % 2 == 1 {
-                        let mut err = |msg: &str| {
-                            tidy_error!(bad, "{}:{start_line}: {msg}", file.display());
-                        };
-                        let block_len = (i + 1) - start_line;
-                        if block_len == 1 {
-                            suppressible_tidy_err!(
-                                err,
-                                skip_odd_backticks,
-                                "comment with odd number of backticks"
-                            );
-                        } else {
-                            suppressible_tidy_err!(
-                                err,
-                                skip_odd_backticks,
-                                "{block_len}-line comment block with odd number of backticks"
-                            );
-                        }
+                } else if let Some((start_line, backtick_count)) = comment_block.take()
+                    && backtick_count % 2 == 1
+                {
+                    let mut err = |msg: &str| {
+                        tidy_error!(bad, "{}:{start_line}: {msg}", file.display());
+                    };
+                    let block_len = (i + 1) - start_line;
+                    if block_len == 1 {
+                        suppressible_tidy_err!(
+                            err,
+                            skip_odd_backticks,
+                            "comment with odd number of backticks"
+                        );
+                    } else {
+                        suppressible_tidy_err!(
+                            err,
+                            skip_odd_backticks,
+                            "{block_len}-line comment block with odd number of backticks"
+                        );
                     }
                 }
             }
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index 1a6fd3eaf2d..f4a6783abb6 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -30,17 +30,17 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                         comp_vec.push(component);
                     }
                 }
-            } else if let Some(compile_flags) = directive.strip_prefix(COMPILE_FLAGS_HEADER) {
-                if let Some((_, v)) = compile_flags.split_once("--target") {
-                    let v = v.trim_start_matches([' ', '=']);
-                    let v = if v == "{{target}}" { Some((v, v)) } else { v.split_once("-") };
-                    if let Some((arch, _)) = v {
-                        let info = header_map.entry(revision).or_insert(RevisionInfo::default());
-                        info.target_arch.replace(arch);
-                    } else {
-                        eprintln!("{file}: seems to have a malformed --target value");
-                        *bad = true;
-                    }
+            } else if let Some(compile_flags) = directive.strip_prefix(COMPILE_FLAGS_HEADER)
+                && let Some((_, v)) = compile_flags.split_once("--target")
+            {
+                let v = v.trim_start_matches([' ', '=']);
+                let v = if v == "{{target}}" { Some((v, v)) } else { v.split_once("-") };
+                if let Some((arch, _)) = v {
+                    let info = header_map.entry(revision).or_insert(RevisionInfo::default());
+                    info.target_arch.replace(arch);
+                } else {
+                    eprintln!("{file}: seems to have a malformed --target value");
+                    *bad = true;
                 }
             }
         });
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 7e295731c56..b9d22ece597 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -161,31 +161,30 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
                     tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
                 }
 
-                if let Ok(metadata) = fs::metadata(file_path) {
-                    if metadata.len() == 0 {
-                        tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
-                    }
+                if let Ok(metadata) = fs::metadata(file_path)
+                    && metadata.len() == 0
+                {
+                    tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
                 }
             }
 
-            if ext == "rs" {
-                if let Some(test_name) = static_regex!(r"^issues?[-_]?(\d{3,})").captures(testname)
-                {
-                    // these paths are always relative to the passed `path` and always UTF8
-                    let stripped_path = file_path
-                        .strip_prefix(path)
-                        .unwrap()
-                        .to_str()
-                        .unwrap()
-                        .replace(std::path::MAIN_SEPARATOR_STR, "/");
-
-                    if !remaining_issue_names.remove(stripped_path.as_str()) {
-                        tidy_error!(
-                            bad,
-                            "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`",
-                            issue_n = &test_name[1],
-                        );
-                    }
+            if ext == "rs"
+                && let Some(test_name) = static_regex!(r"^issues?[-_]?(\d{3,})").captures(testname)
+            {
+                // these paths are always relative to the passed `path` and always UTF8
+                let stripped_path = file_path
+                    .strip_prefix(path)
+                    .unwrap()
+                    .to_str()
+                    .unwrap()
+                    .replace(std::path::MAIN_SEPARATOR_STR, "/");
+
+                if !remaining_issue_names.remove(stripped_path.as_str()) {
+                    tidy_error!(
+                        bad,
+                        "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`",
+                        issue_n = &test_name[1],
+                    );
                 }
             }
         }
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 6a5e9eca813..9f7f43c4000 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -25,12 +25,12 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
                 if let Some(version) = iter.next() {
                     // Check this is the rust-lang/rust x tool installation since it should be
                     // installed at a path containing `src/tools/x`.
-                    if let Some(path) = iter.next() {
-                        if path.contains("src/tools/x") {
-                            let version = version.strip_prefix("v").unwrap();
-                            installed = Some(Version::parse(version).unwrap());
-                            break;
-                        }
+                    if let Some(path) = iter.next()
+                        && path.contains("src/tools/x")
+                    {
+                        let version = version.strip_prefix("v").unwrap();
+                        installed = Some(Version::parse(version).unwrap());
+                        break;
                     };
                 }
             } else {
diff --git a/tests/codegen/enum/enum-discriminant-eq.rs b/tests/codegen/enum/enum-discriminant-eq.rs
new file mode 100644
index 00000000000..0494c5f551b
--- /dev/null
+++ b/tests/codegen/enum/enum-discriminant-eq.rs
@@ -0,0 +1,223 @@
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//@ min-llvm-version: 20
+//@ only-64bit
+
+// The `derive(PartialEq)` on enums with field-less variants compares discriminants,
+// so make sure we emit that in some reasonable way.
+
+#![crate_type = "lib"]
+#![feature(ascii_char)]
+#![feature(core_intrinsics)]
+#![feature(repr128)]
+
+use std::ascii::Char as AC;
+use std::cmp::Ordering;
+use std::intrinsics::discriminant_value;
+use std::num::NonZero;
+
+// A type that's bigger than `isize`, unlike the usual cases that have small tags.
+#[repr(u128)]
+pub enum Giant {
+    Two = 2,
+    Three = 3,
+    Four = 4,
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_bool_eq_discr(a: Option<bool>, b: Option<bool>) -> bool {
+    // CHECK-LABEL: @opt_bool_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i8 %a, 2
+    // CHECK: %[[B:.+]] = icmp eq i8 %b, 2
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_ord_eq_discr(a: Option<Ordering>, b: Option<Ordering>) -> bool {
+    // CHECK-LABEL: @opt_ord_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i8 %a, 2
+    // CHECK: %[[B:.+]] = icmp eq i8 %b, 2
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_nz32_eq_discr(a: Option<NonZero<u32>>, b: Option<NonZero<u32>>) -> bool {
+    // CHECK-LABEL: @opt_nz32_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i32 %a, 0
+    // CHECK: %[[B:.+]] = icmp eq i32 %b, 0
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_ac_eq_discr(a: Option<AC>, b: Option<AC>) -> bool {
+    // CHECK-LABEL: @opt_ac_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i8 %a, -128
+    // CHECK: %[[B:.+]] = icmp eq i8 %b, -128
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn opt_giant_eq_discr(a: Option<Giant>, b: Option<Giant>) -> bool {
+    // CHECK-LABEL: @opt_giant_eq_discr(
+    // CHECK: %[[A:.+]] = icmp ne i128 %a, 1
+    // CHECK: %[[B:.+]] = icmp eq i128 %b, 1
+    // CHECK: %[[R:.+]] = xor i1 %[[A]], %[[B]]
+    // CHECK: ret i1 %[[R]]
+
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+pub enum Mid<T> {
+    Before,
+    Thing(T),
+    After,
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_bool_eq_discr(a: Mid<bool>, b: Mid<bool>) -> bool {
+    // CHECK-LABEL: @mid_bool_eq_discr(
+
+    // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i8 %a, 1
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+
+    // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i8 %b, 1
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ord_eq_discr(a: Mid<Ordering>, b: Mid<Ordering>) -> bool {
+    // CHECK-LABEL: @mid_ord_eq_discr(
+
+    // CHECK: %[[A_REL_DISCR:.+]] = add nsw i8 %a, -2
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp sgt i8 %a, 1
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %[[A_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+
+    // CHECK: %[[B_REL_DISCR:.+]] = add nsw i8 %b, -2
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp sgt i8 %b, 1
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %[[B_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_nz32_eq_discr(a: Mid<NonZero<u32>>, b: Mid<NonZero<u32>>) -> bool {
+    // CHECK-LABEL: @mid_nz32_eq_discr(
+    // CHECK: %[[R:.+]] = icmp eq i32 %a.0, %b.0
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ac_eq_discr(a: Mid<AC>, b: Mid<AC>) -> bool {
+    // CHECK-LABEL: @mid_ac_eq_discr(
+
+    // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+
+    // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+// FIXME: This should be improved once our LLVM fork picks up the fix for
+// <https://github.com/llvm/llvm-project/issues/134024>
+#[unsafe(no_mangle)]
+pub fn mid_giant_eq_discr(a: Mid<Giant>, b: Mid<Giant>) -> bool {
+    // CHECK-LABEL: @mid_giant_eq_discr(
+
+    // CHECK: %[[A_TRUNC:.+]] = trunc nuw nsw i128 %a to i64
+    // CHECK: %[[A_REL_DISCR:.+]] = add nsw i64 %[[A_TRUNC]], -5
+    // CHECK: %[[A_IS_NICHE:.+]] = icmp samesign ugt i128 %a, 4
+    // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i64 %[[A_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
+    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i64 %[[A_REL_DISCR]], i64 1
+
+    // CHECK: %[[B_TRUNC:.+]] = trunc nuw nsw i128 %b to i64
+    // CHECK: %[[B_REL_DISCR:.+]] = add nsw i64 %[[B_TRUNC]], -5
+    // CHECK: %[[B_IS_NICHE:.+]] = icmp samesign ugt i128 %b, 4
+    // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i64 %[[B_REL_DISCR]], 1
+    // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
+    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i64 %[[B_REL_DISCR]], i64 1
+
+    // CHECK: %[[R:.+]] = icmp eq i64 %[[A_DISCR]], %[[B_DISCR]]
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == discriminant_value(&b)
+}
+
+// In niche-encoded enums, testing for the untagged variant should optimize to a
+// straight-forward comparison looking for the natural range of the payload value.
+
+#[unsafe(no_mangle)]
+pub fn mid_bool_is_thing(a: Mid<bool>) -> bool {
+    // CHECK-LABEL: @mid_bool_is_thing(
+    // CHECK: %[[R:.+]] = icmp samesign ult i8 %a, 2
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ord_is_thing(a: Mid<Ordering>) -> bool {
+    // CHECK-LABEL: @mid_ord_is_thing(
+    // CHECK: %[[R:.+]] = icmp slt i8 %a, 2
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_nz32_is_thing(a: Mid<NonZero<u32>>) -> bool {
+    // CHECK-LABEL: @mid_nz32_is_thing(
+    // CHECK: %[[R:.+]] = icmp eq i32 %a.0, 1
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_ac_is_thing(a: Mid<AC>) -> bool {
+    // CHECK-LABEL: @mid_ac_is_thing(
+    // CHECK: %[[R:.+]] = icmp sgt i8 %a, -1
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
+
+#[unsafe(no_mangle)]
+pub fn mid_giant_is_thing(a: Mid<Giant>) -> bool {
+    // CHECK-LABEL: @mid_giant_is_thing(
+    // CHECK: %[[R:.+]] = icmp samesign ult i128 %a, 5
+    // CHECK: ret i1 %[[R]]
+    discriminant_value(&a) == 1
+}
diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs
index 98635008d06..57db44ec74e 100644
--- a/tests/codegen/enum/enum-match.rs
+++ b/tests/codegen/enum/enum-match.rs
@@ -41,7 +41,7 @@ pub enum Enum1 {
 // CHECK-NEXT: start:
 // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
-// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1
 // CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
 // CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
 // CHECK-NEXT: switch i64 %[[DISCR]]
@@ -148,10 +148,10 @@ pub enum MiddleNiche {
 // CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
 // CHECK-NEXT: start:
 // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
-// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5
 // CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
 // CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
-// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2
+// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp{{( samesign)?}} ult i8 %0, 2
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[NOT_NICHE]], i8 2, i8 %[[REL_VAR]]
 // CHECK-NEXT: switch i8 %[[DISCR]]
 #[no_mangle]
 pub fn match4(e: MiddleNiche) -> u8 {
@@ -167,11 +167,10 @@ pub fn match4(e: MiddleNiche) -> u8 {
 
 // CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e)
 // CHECK-NEXT: start
-// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2
-// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4
-// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %e, 4
 // CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
-// CHECK-NEXT: ret i1 %[[NOT_NICHE]]
+// CHECK-NEXT: %[[IS_C:.+]] = icmp{{( samesign)?}} ult i8 %e, 2
+// CHECK-NEXT: ret i1 %[[IS_C]]
 #[no_mangle]
 pub fn match4_is_c(e: MiddleNiche) -> bool {
     // Before #139098, this couldn't optimize out the `select` because it looked
@@ -453,10 +452,10 @@ pub enum HugeVariantIndex {
 // CHECK-NEXT: start:
 // CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
 // CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
-// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3
-// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1
-// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp{{( samesign)?}} ugt i8 %0, 1
 // CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i64 %[[NICHE_DISCR]], 258
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
 // CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258
 // CHECK-NEXT: switch i64 %[[DISCR]],
 // CHECK-NEXT:   i64 257,
@@ -471,3 +470,310 @@ pub fn match5(e: HugeVariantIndex) -> u8 {
         Possible259 => 100,
     }
 }
+
+// Make an enum where the niche tags wrap both as signed and as unsigned, to hit
+// the most-fallback case where there's just nothing smart to do.
+
+pub enum E10Through65 {
+    D10 = 10,
+    D11 = 11,
+    D12 = 12,
+    D13 = 13,
+    D14 = 14,
+    D15 = 15,
+    D16 = 16,
+    D17 = 17,
+    D18 = 18,
+    D19 = 19,
+    D20 = 20,
+    D21 = 21,
+    D22 = 22,
+    D23 = 23,
+    D24 = 24,
+    D25 = 25,
+    D26 = 26,
+    D27 = 27,
+    D28 = 28,
+    D29 = 29,
+    D30 = 30,
+    D31 = 31,
+    D32 = 32,
+    D33 = 33,
+    D34 = 34,
+    D35 = 35,
+    D36 = 36,
+    D37 = 37,
+    D38 = 38,
+    D39 = 39,
+    D40 = 40,
+    D41 = 41,
+    D42 = 42,
+    D43 = 43,
+    D44 = 44,
+    D45 = 45,
+    D46 = 46,
+    D47 = 47,
+    D48 = 48,
+    D49 = 49,
+    D50 = 50,
+    D51 = 51,
+    D52 = 52,
+    D53 = 53,
+    D54 = 54,
+    D55 = 55,
+    D56 = 56,
+    D57 = 57,
+    D58 = 58,
+    D59 = 59,
+    D60 = 60,
+    D61 = 61,
+    D62 = 62,
+    D63 = 63,
+    D64 = 64,
+    D65 = 65,
+}
+
+pub enum Tricky {
+    Untagged(E10Through65),
+    V001,
+    V002,
+    V003,
+    V004,
+    V005,
+    V006,
+    V007,
+    V008,
+    V009,
+    V010,
+    V011,
+    V012,
+    V013,
+    V014,
+    V015,
+    V016,
+    V017,
+    V018,
+    V019,
+    V020,
+    V021,
+    V022,
+    V023,
+    V024,
+    V025,
+    V026,
+    V027,
+    V028,
+    V029,
+    V030,
+    V031,
+    V032,
+    V033,
+    V034,
+    V035,
+    V036,
+    V037,
+    V038,
+    V039,
+    V040,
+    V041,
+    V042,
+    V043,
+    V044,
+    V045,
+    V046,
+    V047,
+    V048,
+    V049,
+    V050,
+    V051,
+    V052,
+    V053,
+    V054,
+    V055,
+    V056,
+    V057,
+    V058,
+    V059,
+    V060,
+    V061,
+    V062,
+    V063,
+    V064,
+    V065,
+    V066,
+    V067,
+    V068,
+    V069,
+    V070,
+    V071,
+    V072,
+    V073,
+    V074,
+    V075,
+    V076,
+    V077,
+    V078,
+    V079,
+    V080,
+    V081,
+    V082,
+    V083,
+    V084,
+    V085,
+    V086,
+    V087,
+    V088,
+    V089,
+    V090,
+    V091,
+    V092,
+    V093,
+    V094,
+    V095,
+    V096,
+    V097,
+    V098,
+    V099,
+    V100,
+    V101,
+    V102,
+    V103,
+    V104,
+    V105,
+    V106,
+    V107,
+    V108,
+    V109,
+    V110,
+    V111,
+    V112,
+    V113,
+    V114,
+    V115,
+    V116,
+    V117,
+    V118,
+    V119,
+    V120,
+    V121,
+    V122,
+    V123,
+    V124,
+    V125,
+    V126,
+    V127,
+    V128,
+    V129,
+    V130,
+    V131,
+    V132,
+    V133,
+    V134,
+    V135,
+    V136,
+    V137,
+    V138,
+    V139,
+    V140,
+    V141,
+    V142,
+    V143,
+    V144,
+    V145,
+    V146,
+    V147,
+    V148,
+    V149,
+    V150,
+    V151,
+    V152,
+    V153,
+    V154,
+    V155,
+    V156,
+    V157,
+    V158,
+    V159,
+    V160,
+    V161,
+    V162,
+    V163,
+    V164,
+    V165,
+    V166,
+    V167,
+    V168,
+    V169,
+    V170,
+    V171,
+    V172,
+    V173,
+    V174,
+    V175,
+    V176,
+    V177,
+    V178,
+    V179,
+    V180,
+    V181,
+    V182,
+    V183,
+    V184,
+    V185,
+    V186,
+    V187,
+    V188,
+    V189,
+    V190,
+    V191,
+    V192,
+    V193,
+    V194,
+    V195,
+    V196,
+    V197,
+    V198,
+    V199,
+    V200,
+}
+
+const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100);
+
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56
+// CHECK-NEXT: %[[TAGGED_DISCR:.+]] = add i8 %e, -65
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[TAGGED_DISCR]], i8 0
+// CHECK-NEXT: ret i8 %[[DISCR]]
+#[no_mangle]
+pub fn discriminant6(e: Tricky) -> u8 {
+    std::intrinsics::discriminant_value(&e) as _
+}
+
+// Case from <https://github.com/rust-lang/rust/issues/104519>,
+// where sign-extension is important.
+
+pub enum OpenResult {
+    Ok(()),
+    Err(()),
+    TransportErr(TransportErr),
+}
+
+#[repr(i32)]
+pub enum TransportErr {
+    UnknownMethod = -2,
+}
+
+#[no_mangle]
+pub fn match7(result: OpenResult) -> u8 {
+    // CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match7(i32{{.+}}%result)
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: %[[NOT_OK:.+]] = icmp ne i32 %result, -1
+    // CHECK-NEXT: %[[RET:.+]] = zext i1 %[[NOT_OK]] to i8
+    // CHECK-NEXT: ret i8 %[[RET]]
+    match result {
+        OpenResult::Ok(()) => 0,
+        _ => 1,
+    }
+}
diff --git a/tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff b/tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff
new file mode 100644
index 00000000000..90a4a509ac1
--- /dev/null
+++ b/tests/mir-opt/inline_double_cycle.a.Inline.panic-abort.diff
@@ -0,0 +1,48 @@
+- // MIR for `a` before Inline
++ // MIR for `a` after Inline
+  
+  fn a() -> () {
+      let mut _0: ();
+      let _1: ();
+      let mut _2: ();
+      let _3: ();
+      let mut _4: ();
++     let mut _5: fn() {a};
++     let mut _6: fn() {b};
++     scope 1 (inlined <fn() {a} as FnOnce<()>>::call_once - shim(fn() {a})) {
++     }
++     scope 2 (inlined <fn() {b} as FnOnce<()>>::call_once - shim(fn() {b})) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+-         _1 = <fn() {a} as FnOnce<()>>::call_once(a, move _2) -> [return: bb1, unwind unreachable];
++         StorageLive(_5);
++         _5 = a;
++         _1 = move _5() -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
++         StorageDead(_5);
+          StorageDead(_2);
+          StorageDead(_1);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = ();
+-         _3 = <fn() {b} as FnOnce<()>>::call_once(b, move _4) -> [return: bb2, unwind unreachable];
++         StorageLive(_6);
++         _6 = b;
++         _3 = move _6() -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
++         StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff b/tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..55da685a3d4
--- /dev/null
+++ b/tests/mir-opt/inline_double_cycle.a.Inline.panic-unwind.diff
@@ -0,0 +1,48 @@
+- // MIR for `a` before Inline
++ // MIR for `a` after Inline
+  
+  fn a() -> () {
+      let mut _0: ();
+      let _1: ();
+      let mut _2: ();
+      let _3: ();
+      let mut _4: ();
++     let mut _5: fn() {a};
++     let mut _6: fn() {b};
++     scope 1 (inlined <fn() {a} as FnOnce<()>>::call_once - shim(fn() {a})) {
++     }
++     scope 2 (inlined <fn() {b} as FnOnce<()>>::call_once - shim(fn() {b})) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+-         _1 = <fn() {a} as FnOnce<()>>::call_once(a, move _2) -> [return: bb1, unwind continue];
++         StorageLive(_5);
++         _5 = a;
++         _1 = move _5() -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
++         StorageDead(_5);
+          StorageDead(_2);
+          StorageDead(_1);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = ();
+-         _3 = <fn() {b} as FnOnce<()>>::call_once(b, move _4) -> [return: bb2, unwind continue];
++         StorageLive(_6);
++         _6 = b;
++         _3 = move _6() -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
++         StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff b/tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff
new file mode 100644
index 00000000000..2090411276c
--- /dev/null
+++ b/tests/mir-opt/inline_double_cycle.b.Inline.panic-abort.diff
@@ -0,0 +1,48 @@
+- // MIR for `b` before Inline
++ // MIR for `b` after Inline
+  
+  fn b() -> () {
+      let mut _0: ();
+      let _1: ();
+      let mut _2: ();
+      let _3: ();
+      let mut _4: ();
++     let mut _5: fn() {b};
++     let mut _6: fn() {a};
++     scope 1 (inlined <fn() {b} as FnOnce<()>>::call_once - shim(fn() {b})) {
++     }
++     scope 2 (inlined <fn() {a} as FnOnce<()>>::call_once - shim(fn() {a})) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+-         _1 = <fn() {b} as FnOnce<()>>::call_once(b, move _2) -> [return: bb1, unwind unreachable];
++         StorageLive(_5);
++         _5 = b;
++         _1 = move _5() -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
++         StorageDead(_5);
+          StorageDead(_2);
+          StorageDead(_1);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = ();
+-         _3 = <fn() {a} as FnOnce<()>>::call_once(a, move _4) -> [return: bb2, unwind unreachable];
++         StorageLive(_6);
++         _6 = a;
++         _3 = move _6() -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
++         StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff b/tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..9e6eef1fa30
--- /dev/null
+++ b/tests/mir-opt/inline_double_cycle.b.Inline.panic-unwind.diff
@@ -0,0 +1,48 @@
+- // MIR for `b` before Inline
++ // MIR for `b` after Inline
+  
+  fn b() -> () {
+      let mut _0: ();
+      let _1: ();
+      let mut _2: ();
+      let _3: ();
+      let mut _4: ();
++     let mut _5: fn() {b};
++     let mut _6: fn() {a};
++     scope 1 (inlined <fn() {b} as FnOnce<()>>::call_once - shim(fn() {b})) {
++     }
++     scope 2 (inlined <fn() {a} as FnOnce<()>>::call_once - shim(fn() {a})) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+-         _1 = <fn() {b} as FnOnce<()>>::call_once(b, move _2) -> [return: bb1, unwind continue];
++         StorageLive(_5);
++         _5 = b;
++         _1 = move _5() -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
++         StorageDead(_5);
+          StorageDead(_2);
+          StorageDead(_1);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = ();
+-         _3 = <fn() {a} as FnOnce<()>>::call_once(a, move _4) -> [return: bb2, unwind continue];
++         StorageLive(_6);
++         _6 = a;
++         _3 = move _6() -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
++         StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline_double_cycle.rs b/tests/mir-opt/inline_double_cycle.rs
new file mode 100644
index 00000000000..cf3b87cf0ad
--- /dev/null
+++ b/tests/mir-opt/inline_double_cycle.rs
@@ -0,0 +1,22 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// skip-filecheck
+//@ test-mir-pass: Inline
+//@ edition: 2021
+//@ compile-flags: -Zinline-mir --crate-type=lib
+
+// EMIT_MIR inline_double_cycle.a.Inline.diff
+// EMIT_MIR inline_double_cycle.b.Inline.diff
+
+#![feature(fn_traits)]
+
+#[inline]
+pub fn a() {
+    FnOnce::call_once(a, ());
+    FnOnce::call_once(b, ());
+}
+
+#[inline]
+pub fn b() {
+    FnOnce::call_once(b, ());
+    FnOnce::call_once(a, ());
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/README.md b/tests/run-make/autodiff/type-trees/type-analysis/README.md
new file mode 100644
index 00000000000..c712edfaf50
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/README.md
@@ -0,0 +1,13 @@
+# Autodiff Type-Trees Type Analysis Tests
+
+This directory contains run-make tests for the autodiff type-trees type analysis functionality. These tests verify that the autodiff compiler correctly analyzes and tracks type information for different Rust types during automatic differentiation.
+
+## What These Tests Do
+
+Each test compiles a simple Rust function with the `#[autodiff_reverse]` attribute and verifies that the compiler:
+
+1. **Correctly identifies type information** in the generated LLVM IR
+2. **Tracks type annotations** for variables and operations
+3. **Preserves type context** through the autodiff transformation process
+
+The tests capture the stdout from the autodiff compiler (which contains type analysis information) and verify it matches expected patterns using FileCheck.
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array/array.check b/tests/run-make/autodiff/type-trees/type-analysis/array/array.check
new file mode 100644
index 00000000000..6e4197692a7
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/array/array.check
@@ -0,0 +1,26 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 4, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 4, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array/array.rs b/tests/run-make/autodiff/type-trees/type-analysis/array/array.rs
new file mode 100644
index 00000000000..9a859418b10
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/array/array.rs
@@ -0,0 +1,20 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &[f32; 3]) -> f32 {
+    x[0] * x[0] + x[1] * x[1] + x[2] * x[2]
+}
+
+fn main() {
+    let x = [1.0f32, 2.0, 3.0];
+    let mut df_dx = [0.0f32; 3];
+    let out = callee(&x);
+    let out_ = d_square(&x, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(2.0, df_dx[0]);
+    assert_eq!(4.0, df_dx[1]);
+    assert_eq!(6.0, df_dx[2]);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs
new file mode 100644
index 00000000000..d68ab46bb94
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/array/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("array.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("array.stdout", stdout);
+    rfs::write("array.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("array.check").stdin_buf(rfs::read("array.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check
new file mode 100644
index 00000000000..ed81ad4869a
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.check
@@ -0,0 +1,54 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ 0.000000e+00, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x [2 x float]], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x float], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw float, ptr %{{[0-9]+}}, i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ 0.000000e+00, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x [2 x float]], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw [2 x float], ptr %{{[0-9]+}}, i64 %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: br label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ]: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = phi i1 [ true, %{{[0-9]+}} ], [ false, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ 0, %{{[0-9]+}} ], [ 1, %{{[0-9]+}} ]: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw float, ptr %{{[0-9]+}}, i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs
new file mode 100644
index 00000000000..a95111a0dae
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/array3d/array3d.rs
@@ -0,0 +1,32 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &[[[f32; 2]; 2]; 2]) -> f32 {
+    let mut sum = 0.0;
+    for i in 0..2 {
+        for j in 0..2 {
+            for k in 0..2 {
+                sum += x[i][j][k] * x[i][j][k];
+            }
+        }
+    }
+    sum
+}
+
+fn main() {
+    let x = [[[1.0f32, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]]];
+    let mut df_dx = [[[0.0f32; 2]; 2]; 2];
+    let out = callee(&x);
+    let out_ = d_square(&x, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    for i in 0..2 {
+        for j in 0..2 {
+            for k in 0..2 {
+                assert_eq!(df_dx[i][j][k], 2.0 * x[i][j][k]);
+            }
+        }
+    }
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs
new file mode 100644
index 00000000000..8e75c21c9d6
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/array3d/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("array3d.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("array3d.stdout", stdout);
+    rfs::write("array3d.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("array3d.check").stdin_buf(rfs::read("array3d.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/box/box.check b/tests/run-make/autodiff/type-trees/type-analysis/box/box.check
new file mode 100644
index 00000000000..1911e18a137
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/box/box.check
@@ -0,0 +1,12 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Pointer, [-1,0,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !{{[0-9]+}}, !align !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Pointer, [-1,0,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Pointer, [-1,0,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !{{[0-9]+}}, !align !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/box/box.rs b/tests/run-make/autodiff/type-trees/type-analysis/box/box.rs
new file mode 100644
index 00000000000..658ccffc74e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/box/box.rs
@@ -0,0 +1,18 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &Box<f32>) -> f32 {
+    **x * **x
+}
+
+fn main() {
+    let x = Box::new(7.0f32);
+    let mut df_dx = Box::new(0.0f32);
+    let out = callee(&x);
+    let out_ = d_square(&x, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(14.0, *df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs
new file mode 100644
index 00000000000..1e8c8f9ccbd
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/box/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("box.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("box.stdout", stdout);
+    rfs::write("box.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("box.check").stdin_buf(rfs::read("box.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check
new file mode 100644
index 00000000000..e7503453f8e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs
new file mode 100644
index 00000000000..8c877bfec05
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/const_pointer.rs
@@ -0,0 +1,18 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: *const f32) -> f32 {
+    unsafe { *x * *x }
+}
+
+fn main() {
+    let x: f32 = 7.0;
+    let out = callee(&x as *const f32);
+    let mut df_dx: f32 = 0.0;
+    let out_ = d_square(&x as *const f32, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(14.0, df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs
new file mode 100644
index 00000000000..ce38c6bd2ae
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/const_pointer/rmake.rs
@@ -0,0 +1,31 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("const_pointer.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("const_pointer.stdout", stdout);
+    rfs::write("const_pointer.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck()
+        .patterns("const_pointer.check")
+        .stdin_buf(rfs::read("const_pointer.stdout"))
+        .run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check
new file mode 100644
index 00000000000..0cc0ffda43d
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.check
@@ -0,0 +1,12 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {} 
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs
new file mode 100644
index 00000000000..b945821934a
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/f32/f32.rs
@@ -0,0 +1,19 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &f32) -> f32 {
+    *x * *x
+}
+
+fn main() {
+    let x: f32 = 7.0;
+    let mut df_dx: f32 = 0.0;
+    let out = callee(&x);
+    let out_ = d_square(&x, &mut df_dx, 1.0);
+
+    assert_eq!(out, out_);
+    assert_eq!(14.0, df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs
new file mode 100644
index 00000000000..d7e49219da6
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/f32/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("f32.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("f32.stdout", stdout);
+    rfs::write("f32.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("f32.check").stdin_buf(rfs::read("f32.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check
new file mode 100644
index 00000000000..efc49da5ffc
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@double} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double}
+// CHECK-DAG: %{{[0-9]+}} = load double, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@double}
+// CHECK-DAG: %{{[0-9]+}} = fmul double %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@double}
+// CHECK-DAG: ret double %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@double} |{[-1]:Pointer, [-1,0]:Float@double}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double}
+// CHECK-DAG: %{{[0-9]+}} = load double, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@double}
+// CHECK-DAG: %{{[0-9]+}} = fmul double %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@double}
+// CHECK-DAG: ret double %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs
new file mode 100644
index 00000000000..9b47569652e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/f64/f64.rs
@@ -0,0 +1,20 @@
+#![feature(autodiff)]
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_callee, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &f64) -> f64 {
+    x * x
+}
+
+fn main() {
+    let x = std::hint::black_box(3.0);
+
+    let output = callee(&x);
+    assert_eq!(9.0, output);
+
+    let mut df_dx = 0.0;
+    let output_ = d_callee(&x, &mut df_dx, 1.0);
+    assert_eq!(output, output_);
+    assert_eq!(6.0, df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs
new file mode 100644
index 00000000000..8bf92b8c1bd
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/f64/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("f64.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("f64.stdout", stdout);
+    rfs::write("f64.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("f64.check").stdin_buf(rfs::read("f64.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check
new file mode 100644
index 00000000000..31a07219e74
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs
new file mode 100644
index 00000000000..19dfbbb22db
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i128/i128.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &i128) -> i128 {
+    *x * *x
+}
+
+fn main() {
+    let x: i128 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs
new file mode 100644
index 00000000000..21e8698634f
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i128/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("i128.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("i128.stdout", stdout);
+    rfs::write("i128.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("i128.check").stdin_buf(rfs::read("i128.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check
new file mode 100644
index 00000000000..8cc299532c5
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs
new file mode 100644
index 00000000000..82099198a2e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i16/i16.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &i16) -> i16 {
+    *x * *x
+}
+
+fn main() {
+    let x: i16 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs
new file mode 100644
index 00000000000..a2875a8c573
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i16/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("i16.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("i16.stdout", stdout);
+    rfs::write("i16.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("i16.check").stdin_buf(rfs::read("i16.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check
new file mode 100644
index 00000000000..4df982887d7
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs
new file mode 100644
index 00000000000..e95068d5c49
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i32/i32.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &i32) -> i32 {
+    *x * *x
+}
+
+fn main() {
+    let x: i32 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs
new file mode 100644
index 00000000000..857017feeab
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i32/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("i32.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("i32.stdout", stdout);
+    rfs::write("i32.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("i32.check").stdin_buf(rfs::read("i32.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check
new file mode 100644
index 00000000000..651a2085bc6
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs
new file mode 100644
index 00000000000..afc0cad703c
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i8/i8.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &i8) -> i8 {
+    *x * *x
+}
+
+fn main() {
+    let x: i8 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs
new file mode 100644
index 00000000000..6551e2d6c4e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/i8/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("i8.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("i8.stdout", stdout);
+    rfs::write("i8.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("i8.check").stdin_buf(rfs::read("i8.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check
new file mode 100644
index 00000000000..40ee6edc02c
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs
new file mode 100644
index 00000000000..dd160984a4e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/isize/isize.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &isize) -> isize {
+    *x * *x
+}
+
+fn main() {
+    let x: isize = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs
new file mode 100644
index 00000000000..09277f63ed4
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/isize/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("isize.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("isize.stdout", stdout);
+    rfs::write("isize.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("isize.check").stdin_buf(rfs::read("isize.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check
new file mode 100644
index 00000000000..e7503453f8e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs
new file mode 100644
index 00000000000..2b672f6d3f8
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/mut_pointer.rs
@@ -0,0 +1,18 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: *mut f32) -> f32 {
+    unsafe { *x * *x }
+}
+
+fn main() {
+    let mut x: f32 = 7.0;
+    let out = callee(&mut x as *mut f32);
+    let mut df_dx: f32 = 0.0;
+    let out_ = d_square(&mut x as *mut f32, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(14.0, df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs
new file mode 100644
index 00000000000..4d5a5042141
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_pointer/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("mut_pointer.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("mut_pointer.stdout", stdout);
+    rfs::write("mut_pointer.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("mut_pointer.check").stdin_buf(rfs::read("mut_pointer.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check
new file mode 100644
index 00000000000..e7503453f8e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs
new file mode 100644
index 00000000000..7019e3f71ed
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/mut_ref.rs
@@ -0,0 +1,18 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &mut f32) -> f32 {
+    *x * *x
+}
+
+fn main() {
+    let mut x: f32 = 7.0;
+    let mut df_dx: f32 = 0.0;
+    let out = callee(&mut x);
+    let out_ = d_square(&mut x, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(14.0, df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs
new file mode 100644
index 00000000000..13668c54e78
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/mut_ref/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("mut_ref.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("mut_ref.stdout", stdout);
+    rfs::write("mut_ref.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("mut_ref.check").stdin_buf(rfs::read("mut_ref.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check
new file mode 100644
index 00000000000..e7503453f8e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs
new file mode 100644
index 00000000000..3ced164b86f
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/ref/ref.rs
@@ -0,0 +1,18 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &f32) -> f32 {
+    *x * *x
+}
+
+fn main() {
+    let x: f32 = 7.0;
+    let mut df_dx: f32 = 0.0;
+    let out = callee(&x);
+    let out_ = d_square(&x, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(14.0, df_dx);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs
new file mode 100644
index 00000000000..b68e4e5b8ac
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/ref/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("ref.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("ref.stdout", stdout);
+    rfs::write("ref.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("ref.check").stdin_buf(rfs::read("ref.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs
new file mode 100644
index 00000000000..4073f7554cc
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/struct/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("struct.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("struct.stdout", stdout);
+    rfs::write("struct.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("struct.check").stdin_buf(rfs::read("struct.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check
new file mode 100644
index 00000000000..e7503453f8e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs
new file mode 100644
index 00000000000..52cb6a9a6b9
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/struct/struct.rs
@@ -0,0 +1,23 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[derive(Copy, Clone)]
+struct MyStruct {
+    f: f32,
+}
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &MyStruct) -> f32 {
+    x.f * x.f
+}
+
+fn main() {
+    let x = MyStruct { f: 7.0 };
+    let mut df_dx = MyStruct { f: 0.0 };
+    let out = callee(&x);
+    let out_ = d_square(&x, &mut df_dx, 1.0);
+    assert_eq!(out, out_);
+    assert_eq!(14.0, df_dx.f);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs
new file mode 100644
index 00000000000..3f605d47c68
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u128/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("u128.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("u128.stdout", stdout);
+    rfs::write("u128.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("u128.check").stdin_buf(rfs::read("u128.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check
new file mode 100644
index 00000000000..31a07219e74
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer, [-1,12]:Integer, [-1,13]:Integer, [-1,14]:Integer, [-1,15]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i128, ptr %{{[0-9]+}}, align 16, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i128 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i128 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs
new file mode 100644
index 00000000000..d19d2faa51b
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u128/u128.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &u128) -> u128 {
+    *x * *x
+}
+
+fn main() {
+    let x: u128 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs
new file mode 100644
index 00000000000..0051f6f9795
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u16/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("u16.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("u16.stdout", stdout);
+    rfs::write("u16.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("u16.check").stdin_buf(rfs::read("u16.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check
new file mode 100644
index 00000000000..8cc299532c5
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i16, ptr %{{[0-9]+}}, align 2, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i16 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i16 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs
new file mode 100644
index 00000000000..f5f5b50622b
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u16/u16.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &u16) -> u16 {
+    *x * *x
+}
+
+fn main() {
+    let x: u16 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs
new file mode 100644
index 00000000000..0882230b1c6
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u32/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("u32.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("u32.stdout", stdout);
+    rfs::write("u32.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("u32.check").stdin_buf(rfs::read("u32.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check
new file mode 100644
index 00000000000..4df982887d7
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i32, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i32 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i32 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs
new file mode 100644
index 00000000000..66b4c222c51
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u32/u32.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &u32) -> u32 {
+    *x * *x
+}
+
+fn main() {
+    let x: u32 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs
new file mode 100644
index 00000000000..100b4f498f2
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u8/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("u8.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("u8.stdout", stdout);
+    rfs::write("u8.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("u8.check").stdin_buf(rfs::read("u8.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check
new file mode 100644
index 00000000000..651a2085bc6
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i8, ptr %{{[0-9]+}}, align 1, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i8 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i8 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs
new file mode 100644
index 00000000000..de9cdeb631e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/u8/u8.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &u8) -> u8 {
+    *x * *x
+}
+
+fn main() {
+    let x: u8 = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs
new file mode 100644
index 00000000000..67f0fe18481
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/union/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("union.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("union.stdout", stdout);
+    rfs::write("union.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("union.check").stdin_buf(rfs::read("union.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/union/union.check b/tests/run-make/autodiff/type-trees/type-analysis/union/union.check
new file mode 100644
index 00000000000..e7503453f8e
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/union/union.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer, [-1,0]:Float@float}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fmul float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/union/union.rs b/tests/run-make/autodiff/type-trees/type-analysis/union/union.rs
new file mode 100644
index 00000000000..8d997f8c839
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/union/union.rs
@@ -0,0 +1,20 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[allow(dead_code)]
+union MyUnion {
+    f: f32,
+    i: i32,
+}
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &MyUnion) -> f32 {
+    unsafe { x.f * x.f }
+}
+
+fn main() {
+    let x = MyUnion { f: 7.0 };
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs
new file mode 100644
index 00000000000..d5cfd708c3a
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/usize/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("usize.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("usize.stdout", stdout);
+    rfs::write("usize.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("usize.check").stdin_buf(rfs::read("usize.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check
new file mode 100644
index 00000000000..40ee6edc02c
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.check
@@ -0,0 +1,10 @@
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK: callee - {[-1]:Integer} |{[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Integer, [-1,1]:Integer, [-1,2]:Integer, [-1,3]:Integer, [-1,4]:Integer, [-1,5]:Integer, [-1,6]:Integer, [-1,7]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = mul i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: ret i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs
new file mode 100644
index 00000000000..8e758be57d4
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/usize/usize.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(x: &usize) -> usize {
+    *x * *x
+}
+
+fn main() {
+    let x: usize = 7;
+    let _ = callee(&x);
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs b/tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs
new file mode 100644
index 00000000000..94491fab8d6
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/rmake.rs
@@ -0,0 +1,28 @@
+//@ needs-enzyme
+//@ ignore-cross-compile
+
+use std::fs;
+
+use run_make_support::{llvm_filecheck, rfs, rustc};
+
+fn main() {
+    // Compile the Rust file with the required flags, capturing both stdout and stderr
+    let output = rustc()
+        .input("vec.rs")
+        .arg("-Zautodiff=Enable,PrintTAFn=callee")
+        .arg("-Zautodiff=NoPostopt")
+        .opt_level("3")
+        .arg("-Clto=fat")
+        .arg("-g")
+        .run();
+
+    let stdout = output.stdout_utf8();
+    let stderr = output.stderr_utf8();
+
+    // Write the outputs to files
+    rfs::write("vec.stdout", stdout);
+    rfs::write("vec.stderr", stderr);
+
+    // Run FileCheck on the stdout using the check file
+    llvm_filecheck().patterns("vec.check").stdin_buf(rfs::read("vec.stdout")).run();
+}
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check
new file mode 100644
index 00000000000..dcf9508b69d
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check
@@ -0,0 +1,18 @@
+// CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{}
+// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer}
+// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !102, !noundef !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 16, !dbg !{{[0-9]+}}: {[-1]:Pointer}
+// CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = icmp eq i64 %{{[0-9]+}}, 0, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi i64 [ %{{[0-9]+}}, %{{[0-9]+}} ], [ 0, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ %{{[0-9]+}}, %{{[0-9]+}} ], [ -0.000000e+00, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw float, ptr %{{[0-9]+}}, i64 %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = load float, ptr %{{[0-9]+}}, align 4, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = fadd float %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: %{{[0-9]+}} = add nuw i64 %{{[0-9]+}}, 1, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: %{{[0-9]+}} = icmp eq i64 %{{[0-9]+}}, %{{[0-9]+}}, !dbg !{{[0-9]+}}: {[-1]:Integer}
+// CHECK-DAG: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
+// CHECK-DAG: %{{[0-9]+}} = phi float [ -0.000000e+00, %{{[0-9]+}} ], [ %{{[0-9]+}}, %{{[0-9]+}} ], !dbg !{{[0-9]+}}: {[-1]:Float@float}
+// CHECK-DAG: ret float %{{[0-9]+}}, !dbg !{{[0-9]+}}: {}
\ No newline at end of file
diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs
new file mode 100644
index 00000000000..b60c2a88064
--- /dev/null
+++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.rs
@@ -0,0 +1,14 @@
+#![feature(autodiff)]
+
+use std::autodiff::autodiff_reverse;
+
+#[autodiff_reverse(d_square, Duplicated, Active)]
+#[no_mangle]
+fn callee(arg: &std::vec::Vec<f32>) -> f32 {
+    arg.iter().sum()
+}
+
+fn main() {
+    let v = vec![1.0f32, 2.0, 3.0];
+    let _ = callee(&v);
+}
diff --git a/tests/run-make/link-eh-frame-terminator/rmake.rs b/tests/run-make/link-eh-frame-terminator/rmake.rs
index 6bfae386ea1..06b77f011ec 100644
--- a/tests/run-make/link-eh-frame-terminator/rmake.rs
+++ b/tests/run-make/link-eh-frame-terminator/rmake.rs
@@ -9,6 +9,7 @@
 //@ ignore-32bit
 // Reason: the usage of a large array in the test causes an out-of-memory
 // error on 32 bit systems.
+//@ ignore-cross-compile
 
 use run_make_support::{bin_name, llvm_objdump, run, rustc};
 
diff --git a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs
new file mode 100644
index 00000000000..96fa8209cde
--- /dev/null
+++ b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs
@@ -0,0 +1,14 @@
+#[unsafe(no_mangle)]
+pub fn f0() {}
+
+#[unsafe(link_section = ".here")]
+pub fn f1() {}
+
+#[unsafe(export_name = "f2export")]
+pub fn f2() {}
+
+#[repr(u8)]
+pub enum T0 { V1 }
+
+#[non_exhaustive]
+pub enum T1 {}
diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs
new file mode 100644
index 00000000000..0ec645841f0
--- /dev/null
+++ b/tests/rustdoc/reexport/reexport-attrs.rs
@@ -0,0 +1,20 @@
+//@ aux-build: reexports-attrs.rs
+
+#![crate_name = "foo"]
+
+extern crate reexports_attrs;
+
+//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[no_mangle]'
+pub use reexports_attrs::f0;
+
+//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[link_section = ".here"]'
+pub use reexports_attrs::f1;
+
+//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[export_name = "f2export"]'
+pub use reexports_attrs::f2;
+
+//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]'
+pub use reexports_attrs::T0;
+
+//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
+pub use reexports_attrs::T1;
diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs
index b90bb9ea4dd..029ce7d0e7e 100644
--- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs
+++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs
@@ -1,8 +1,7 @@
 // Regression test for <https://github.com/rust-lang/rust/issues/137554>.
 
 fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
-    //~^ ERROR `?Trait` is not permitted in trait object types
-    //~| ERROR expected trait, found associated function `Iterator::advance_by`
-    //~| ERROR the value of the associated type `Item` in `Iterator` must be specified
+    //~^ ERROR expected trait, found associated function `Iterator::advance_by`
+    //~| ERROR relaxed bounds are not permitted in trait object types
     todo!()
 }
diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr
index 7f0fbc800ed..ffe0b14a030 100644
--- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr
+++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr
@@ -1,25 +1,15 @@
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29
-   |
-LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0404]: expected trait, found associated function `Iterator::advance_by`
   --> $DIR/missing-associated_item_or_field_def_ids.rs:3:30
    |
 LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait
 
-error[E0191]: the value of the associated type `Item` in `Iterator` must be specified
-  --> $DIR/missing-associated_item_or_field_def_ids.rs:3:18
+error: relaxed bounds are not permitted in trait object types
+  --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29
    |
 LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) {
-   |                  ^^^^^^^^ help: specify the associated type: `Iterator<Item = Type>`
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0191, E0404, E0658.
-For more information about an error, try `rustc --explain E0191`.
+For more information about this error, try `rustc --explain E0404`.
diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs
index f6b749a5100..bac4e608867 100644
--- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs
+++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs
@@ -6,7 +6,6 @@ trait Tr {
 
 fn main() {
     let _: dyn Tr + ?Foo<Assoc = ()>;
-    //~^ ERROR: `?Trait` is not permitted in trait object types
-    //~| ERROR: cannot find trait `Foo` in this scope
-    //~| ERROR: the value of the associated type `Item` in `Tr` must be specified
+    //~^ ERROR: cannot find trait `Foo` in this scope
+    //~| ERROR: relaxed bounds are not permitted in trait object types
 }
diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr
index f31a1de76a7..3660fcece62 100644
--- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr
+++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr
@@ -1,28 +1,15 @@
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21
-   |
-LL |     let _: dyn Tr + ?Foo<Assoc = ()>;
-   |                     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0405]: cannot find trait `Foo` in this scope
   --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:22
    |
 LL |     let _: dyn Tr + ?Foo<Assoc = ()>;
    |                      ^^^ not found in this scope
 
-error[E0191]: the value of the associated type `Item` in `Tr` must be specified
-  --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:16
+error: relaxed bounds are not permitted in trait object types
+  --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21
    |
-LL |     type Item;
-   |     --------- `Item` defined here
-...
 LL |     let _: dyn Tr + ?Foo<Assoc = ()>;
-   |                ^^ help: specify the associated type: `Tr<Item = Type>`
+   |                     ^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0191, E0405, E0658.
-For more information about an error, try `rustc --explain E0191`.
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
index 92b226fe0f7..0c57eddbe93 100644
--- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
+++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
@@ -1,8 +1,12 @@
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory
   --> $DIR/invalid-patterns.rs:40:32
    |
 LL |   get_flag::<false, { unsafe { char_raw.character } }>();
    |                                ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#7}` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ff __ __ __                                     │ .░░░
+           }
 
 error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean
   --> $DIR/invalid-patterns.rs:42:14
@@ -26,11 +30,15 @@ LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character
                42                                              │ B
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory
   --> $DIR/invalid-patterns.rs:44:58
    |
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |                                                          ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#11}` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ff __ __ __                                     │ .░░░
+           }
 
 error[E0308]: mismatched types
   --> $DIR/invalid-patterns.rs:31:21
diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
index 92b226fe0f7..0c57eddbe93 100644
--- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
+++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
@@ -1,8 +1,12 @@
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory
   --> $DIR/invalid-patterns.rs:40:32
    |
 LL |   get_flag::<false, { unsafe { char_raw.character } }>();
    |                                ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#7}` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ff __ __ __                                     │ .░░░
+           }
 
 error[E0080]: constructing invalid value: encountered 0x42, but expected a boolean
   --> $DIR/invalid-patterns.rs:42:14
@@ -26,11 +30,15 @@ LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character
                42                                              │ B
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory
   --> $DIR/invalid-patterns.rs:44:58
    |
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |                                                          ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#11}` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ff __ __ __                                     │ .░░░
+           }
 
 error[E0308]: mismatched types
   --> $DIR/invalid-patterns.rs:31:21
diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr
index c1706a8c4b0..770a55cc726 100644
--- a/tests/ui/consts/const-compare-bytes-ub.stderr
+++ b/tests/ui/consts/const-compare-bytes-ub.stderr
@@ -33,12 +33,20 @@ error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at
    |
 LL |         compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::LHS_UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               __                                              │ ░
+           }
 
 error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
   --> $DIR/const-compare-bytes-ub.rs:33:9
    |
 LL |         compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::RHS_UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               __                                              │ ░
+           }
 
 error[E0080]: unable to turn pointer into integer
   --> $DIR/const-compare-bytes-ub.rs:37:9
diff --git a/tests/ui/consts/const-err-enum-discriminant.32bit.stderr b/tests/ui/consts/const-err-enum-discriminant.32bit.stderr
new file mode 100644
index 00000000000..cc786108f64
--- /dev/null
+++ b/tests/ui/consts/const-err-enum-discriminant.32bit.stderr
@@ -0,0 +1,13 @@
+error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
+  --> $DIR/const-err-enum-discriminant.rs:10:21
+   |
+LL |     Boo = [unsafe { Foo { b: () }.a }; 4][3],
+   |                     ^^^^^^^^^^^^^^^ evaluation of `Bar::Boo::{constant#0}` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               __ __ __ __                                     │ ░░░░
+           }
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-err-enum-discriminant.64bit.stderr b/tests/ui/consts/const-err-enum-discriminant.64bit.stderr
new file mode 100644
index 00000000000..1d32851aac1
--- /dev/null
+++ b/tests/ui/consts/const-err-enum-discriminant.64bit.stderr
@@ -0,0 +1,13 @@
+error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory
+  --> $DIR/const-err-enum-discriminant.rs:10:21
+   |
+LL |     Boo = [unsafe { Foo { b: () }.a }; 4][3],
+   |                     ^^^^^^^^^^^^^^^ evaluation of `Bar::Boo::{constant#0}` failed here
+   |
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               __ __ __ __ __ __ __ __                         │ ░░░░░░░░
+           }
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-err-enum-discriminant.rs b/tests/ui/consts/const-err-enum-discriminant.rs
index 190ef47f436..55674600584 100644
--- a/tests/ui/consts/const-err-enum-discriminant.rs
+++ b/tests/ui/consts/const-err-enum-discriminant.rs
@@ -1,3 +1,5 @@
+//@ stderr-per-bitwidth
+
 #[derive(Copy, Clone)]
 union Foo {
     a: isize,
diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.stderr
deleted file mode 100644
index 8724333ad7a..00000000000
--- a/tests/ui/consts/const-err-enum-discriminant.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0080]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/const-err-enum-discriminant.rs:8:21
-   |
-LL |     Boo = [unsafe { Foo { b: () }.a }; 4][3],
-   |                     ^^^^^^^^^^^^^^^ evaluation of `Bar::Boo::{constant#0}` failed here
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
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 d28d6841ca9..60f6ef0f64b 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
@@ -43,11 +43,15 @@ LL |     const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin
    = 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]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC2[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory
   --> $DIR/const-pointer-values-in-various-types.rs:42:47
    |
 LL |     const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_U128_UNION` failed here
+   |
+   = note: the raw bytes of the constant (size: 16, align: 16) {
+               ╾ALLOC0<imm>╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░
+           }
 
 error[E0080]: unable to turn pointer into integer
   --> $DIR/const-pointer-values-in-various-types.rs:45:43
@@ -85,11 +89,15 @@ LL |     const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int
    = 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]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC3[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory
   --> $DIR/const-pointer-values-in-various-types.rs:57:47
    |
 LL |     const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::I32_REF_I128_UNION` failed here
+   |
+   = note: the raw bytes of the constant (size: 16, align: 16) {
+               ╾ALLOC1<imm>╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░
+           }
 
 error[E0080]: unable to turn pointer into integer
   --> $DIR/const-pointer-values-in-various-types.rs:60:45
diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr
index 52af52d3236..2fd01b67c49 100644
--- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr
+++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr
@@ -1,8 +1,12 @@
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x1..0x2], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
   --> $DIR/ub-enum-overwrite.rs:11:14
    |
 LL |     unsafe { *p }
    |              ^^ evaluation of `_` failed here
+   |
+   = note: the raw bytes of the constant (size: 2, align: 1) {
+               01 __                                           │ .░
+           }
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs
index 52fc9945068..9c78bb6efed 100644
--- a/tests/ui/consts/const-eval/ub-enum.rs
+++ b/tests/ui/consts/const-eval/ub-enum.rs
@@ -1,7 +1,8 @@
 // Strip out raw byte dumps to make comparison platform-independent:
 //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
+//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 //@ normalize-stderr: "0x0+" -> "0x0"
+//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1"
 //@ dont-require-annotations: NOTE
 
 #![feature(never_type)]
diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr
index 29f7a1f051a..5cbd6176c92 100644
--- a/tests/ui/consts/const-eval/ub-enum.stderr
+++ b/tests/ui/consts/const-eval/ub-enum.stderr
@@ -1,5 +1,5 @@
 error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x01, but expected a valid enum tag
-  --> $DIR/ub-enum.rs:29:1
+  --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
    | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
            }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-enum.rs:32:1
+  --> $DIR/ub-enum.rs:33:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM_PTR` failed here
@@ -19,7 +19,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-enum.rs:35:1
+  --> $DIR/ub-enum.rs:36:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM_WRAPPED` failed here
@@ -28,7 +28,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x0, but expected a valid enum tag
-  --> $DIR/ub-enum.rs:47:1
+  --> $DIR/ub-enum.rs:48:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -39,7 +39,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-enum.rs:49:1
+  --> $DIR/ub-enum.rs:50:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_PTR` failed here
@@ -48,7 +48,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-enum.rs:52:1
+  --> $DIR/ub-enum.rs:53:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_WRAPPED` failed here
@@ -56,14 +56,18 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = 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]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/ub-enum.rs:61:41
+error[E0080]: reading memory at ALLOC0[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-enum.rs:62:41
    |
 LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_UNDEF` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-enum.rs:65:1
+  --> $DIR/ub-enum.rs:66:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_ENUM2_OPTION_PTR` failed here
@@ -72,7 +76,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
-  --> $DIR/ub-enum.rs:82:1
+  --> $DIR/ub-enum.rs:83:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -83,7 +87,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute
            }
 
 error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
-  --> $DIR/ub-enum.rs:84:1
+  --> $DIR/ub-enum.rs:85:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -94,7 +98,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute
            }
 
 error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
-  --> $DIR/ub-enum.rs:92:1
+  --> $DIR/ub-enum.rs:93:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -105,19 +109,19 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
            }
 
 error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
-  --> $DIR/ub-enum.rs:97:77
+  --> $DIR/ub-enum.rs:98:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA1` failed here
 
 error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant
-  --> $DIR/ub-enum.rs:99:77
+  --> $DIR/ub-enum.rs:100:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
    |                                                                             ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA2` failed here
 
 error[E0080]: read discriminant of an uninhabited enum variant
-  --> $DIR/ub-enum.rs:105:9
+  --> $DIR/ub-enum.rs:106:9
    |
 LL |         std::mem::discriminant(&*(&() as *const () as *const Never));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TEST_ICE_89765` failed inside this call
diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr
index 314141e4837..19ae66cf3c6 100644
--- a/tests/ui/consts/const-eval/ub-nonnull.stderr
+++ b/tests/ui/consts/const-eval/ub-nonnull.stderr
@@ -37,11 +37,15 @@ LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
                HEX_DUMP
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
   --> $DIR/ub-nonnull.rs:36:38
    |
 LL | const UNINIT: NonZero<u8> = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               __                                              │ ░
+           }
 
 error[E0080]: constructing invalid value: encountered 42, but expected something in the range 10..=30
   --> $DIR/ub-nonnull.rs:44:1
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs
index 64b48939be6..d8e5102fcbe 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.rs
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs
@@ -1,8 +1,9 @@
 // ignore-tidy-linelength
 // Strip out raw byte dumps to make comparison platform-independent:
 //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
+//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 //@ dont-require-annotations: NOTE
+//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1"
 
 #![allow(invalid_value)]
 
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index d5ccc396b90..451ebb6eba1 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -1,5 +1,5 @@
 error[E0080]: constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
-  --> $DIR/ub-ref-ptr.rs:17:1
+  --> $DIR/ub-ref-ptr.rs:18:1
    |
 LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -10,7 +10,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
-  --> $DIR/ub-ref-ptr.rs:20:1
+  --> $DIR/ub-ref-ptr.rs:21:1
    |
 LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -21,7 +21,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
            }
 
 error[E0080]: constructing invalid value: encountered a null reference
-  --> $DIR/ub-ref-ptr.rs:23:1
+  --> $DIR/ub-ref-ptr.rs:24:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -32,7 +32,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: constructing invalid value: encountered a null box
-  --> $DIR/ub-ref-ptr.rs:26:1
+  --> $DIR/ub-ref-ptr.rs:27:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
            }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-ref-ptr.rs:33:1
+  --> $DIR/ub-ref-ptr.rs:34:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE` failed here
@@ -52,7 +52,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-ref-ptr.rs:36:39
+  --> $DIR/ub-ref-ptr.rs:37:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_SLICE` failed here
@@ -61,13 +61,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant encountered
-  --> $DIR/ub-ref-ptr.rs:36:38
+  --> $DIR/ub-ref-ptr.rs:37:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-ref-ptr.rs:39:86
+  --> $DIR/ub-ref-ptr.rs:40:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_BOX_SLICE` failed here
@@ -76,13 +76,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant encountered
-  --> $DIR/ub-ref-ptr.rs:39:85
+  --> $DIR/ub-ref-ptr.rs:40:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance)
-  --> $DIR/ub-ref-ptr.rs:42:1
+  --> $DIR/ub-ref-ptr.rs:43:1
    |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -93,7 +93,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance)
-  --> $DIR/ub-ref-ptr.rs:45:1
+  --> $DIR/ub-ref-ptr.rs:46:1
    |
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -103,14 +103,18 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
                HEX_DUMP
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/ub-ref-ptr.rs:48:41
+error[E0080]: reading memory at ALLOC3[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-ref-ptr.rs:49:41
    |
 LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_PTR` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer
-  --> $DIR/ub-ref-ptr.rs:51:1
+  --> $DIR/ub-ref-ptr.rs:52:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -120,14 +124,18 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
                HEX_DUMP
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/ub-ref-ptr.rs:53:38
+error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-ref-ptr.rs:54:38
    |
 LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_FN_PTR` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
-  --> $DIR/ub-ref-ptr.rs:55:1
+  --> $DIR/ub-ref-ptr.rs:56:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -138,7 +146,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
            }
 
 error[E0080]: constructing invalid value: encountered ALLOC2<imm>, but expected a function pointer
-  --> $DIR/ub-ref-ptr.rs:57:1
+  --> $DIR/ub-ref-ptr.rs:58:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -149,7 +157,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
            }
 
 error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required
-  --> $DIR/ub-ref-ptr.rs:64:5
+  --> $DIR/ub-ref-ptr.rs:65:5
    |
 LL |     ptr.read();
    |     ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs
index 86235897e7e..0bbb104c032 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs
@@ -6,9 +6,10 @@ use std::{ptr, mem};
 
 // Strip out raw byte dumps to make comparison platform-independent:
 //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
+//@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 //@ normalize-stderr: "offset \d+" -> "offset N"
 //@ normalize-stderr: "size \d+" -> "size N"
+//@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1"
 //@ dont-require-annotations: NOTE
 
 /// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error
@@ -61,7 +62,7 @@ const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::
 const SLICE_VALID: &[u8] = unsafe { mem::transmute((&42u8, 1usize)) };
 // bad slice: length uninit
 const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
-//~^ ERROR uninitialized
+    //~^ ERROR uninitialized
     let uninit_len = MaybeUninit::<usize> { uninit: () };
     mem::transmute((42, uninit_len))
 };
@@ -99,7 +100,7 @@ const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) };
 const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw
 const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw
 const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
-//~^ ERROR uninitialized
+    //~^ ERROR uninitialized
     let uninit_len = MaybeUninit::<usize> { uninit: () };
     mem::transmute((42, uninit_len))
 };
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
index 8724dd9a3c0..ab15ba826a5 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -1,5 +1,5 @@
 error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
-  --> $DIR/ub-wide-ptr.rs:39:1
+  --> $DIR/ub-wide-ptr.rs:40:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -10,7 +10,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
            }
 
 error[E0080]: constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
-  --> $DIR/ub-wide-ptr.rs:41:1
+  --> $DIR/ub-wide-ptr.rs:42:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -21,7 +21,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us
            }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-wide-ptr.rs:44:1
+  --> $DIR/ub-wide-ptr.rs:45:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `STR_LENGTH_PTR` failed here
@@ -30,7 +30,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-wide-ptr.rs:47:1
+  --> $DIR/ub-wide-ptr.rs:48:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `MY_STR_LENGTH_PTR` failed here
@@ -39,7 +39,7 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
-  --> $DIR/ub-wide-ptr.rs:49:1
+  --> $DIR/ub-wide-ptr.rs:50:1
    |
 LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -50,7 +50,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize:
            }
 
 error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected a string
-  --> $DIR/ub-wide-ptr.rs:53:1
+  --> $DIR/ub-wide-ptr.rs:54:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -61,7 +61,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:
            }
 
 error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialized memory, but expected a string
-  --> $DIR/ub-wide-ptr.rs:56:1
+  --> $DIR/ub-wide-ptr.rs:57:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -71,14 +71,18 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni
                HEX_DUMP
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/ub-wide-ptr.rs:63:1
+error[E0080]: reading memory at ALLOC32[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-wide-ptr.rs:64:1
    |
 LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
-  --> $DIR/ub-wide-ptr.rs:69:1
+  --> $DIR/ub-wide-ptr.rs:70:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -89,7 +93,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
            }
 
 error[E0080]: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
-  --> $DIR/ub-wide-ptr.rs:72:1
+  --> $DIR/ub-wide-ptr.rs:73:1
    |
 LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -100,7 +104,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is
            }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-wide-ptr.rs:75:1
+  --> $DIR/ub-wide-ptr.rs:76:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_PTR` failed here
@@ -109,7 +113,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
-  --> $DIR/ub-wide-ptr.rs:78:1
+  --> $DIR/ub-wide-ptr.rs:79:1
    |
 LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -120,7 +124,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us
            }
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-wide-ptr.rs:81:1
+  --> $DIR/ub-wide-ptr.rs:82:1
    |
 LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SLICE_LENGTH_PTR_BOX` failed here
@@ -129,7 +133,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
-  --> $DIR/ub-wide-ptr.rs:85:1
+  --> $DIR/ub-wide-ptr.rs:86:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -140,13 +144,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
            }
 
 note: erroneous constant encountered
-  --> $DIR/ub-wide-ptr.rs:85:40
+  --> $DIR/ub-wide-ptr.rs:86:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
-  --> $DIR/ub-wide-ptr.rs:91:1
+  --> $DIR/ub-wide-ptr.rs:92:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -157,13 +161,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3
            }
 
 note: erroneous constant encountered
-  --> $DIR/ub-wide-ptr.rs:91:42
+  --> $DIR/ub-wide-ptr.rs:92:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
-  --> $DIR/ub-wide-ptr.rs:94:1
+  --> $DIR/ub-wide-ptr.rs:95:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -174,19 +178,23 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran
            }
 
 note: erroneous constant encountered
-  --> $DIR/ub-wide-ptr.rs:94:42
+  --> $DIR/ub-wide-ptr.rs:95:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/ub-wide-ptr.rs:101:1
+error[E0080]: reading memory at ALLOC33[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-wide-ptr.rs:102:1
    |
 LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_SLICE_LENGTH_UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: constructing invalid value at .0: encountered ALLOC12<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:109:1
+  --> $DIR/ub-wide-ptr.rs:110:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -197,7 +205,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: constructing invalid value at .0: encountered ALLOC14<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:112:1
+  --> $DIR/ub-wide-ptr.rs:113:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -208,7 +216,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
            }
 
 error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:115:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -219,7 +227,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u
            }
 
 error[E0080]: constructing invalid value: encountered ALLOC17<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:117:1
+  --> $DIR/ub-wide-ptr.rs:118:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -230,7 +238,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92
            }
 
 error[E0080]: constructing invalid value: encountered ALLOC19<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:119:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -241,7 +249,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92
            }
 
 error[E0080]: constructing invalid value: encountered ALLOC21<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:121:1
+  --> $DIR/ub-wide-ptr.rs:122:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -252,7 +260,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u
            }
 
 error[E0080]: constructing invalid value at .0: encountered ALLOC23<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:123:1
+  --> $DIR/ub-wide-ptr.rs:124:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -263,7 +271,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
            }
 
 error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
-  --> $DIR/ub-wide-ptr.rs:127:1
+  --> $DIR/ub-wide-ptr.rs:128:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -274,7 +282,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
            }
 
 error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:131:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -285,7 +293,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
            }
 
 error[E0080]: constructing invalid value: encountered ALLOC28<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:133:1
+  --> $DIR/ub-wide-ptr.rs:134:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -296,7 +304,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
            }
 
 error[E0080]: constructing invalid value: encountered null pointer, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:140:1
+  --> $DIR/ub-wide-ptr.rs:141:1
    |
 LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -307,7 +315,7 @@ LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe
            }
 
 error[E0080]: constructing invalid value: encountered ALLOC31<imm>, but expected a vtable pointer
-  --> $DIR/ub-wide-ptr.rs:144:1
+  --> $DIR/ub-wide-ptr.rs:145:1
    |
 LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs
index 0ad94eee7f4..719e59b007c 100644
--- a/tests/ui/consts/const-eval/union-const-eval-field.rs
+++ b/tests/ui/consts/const-eval/union-const-eval-field.rs
@@ -1,4 +1,5 @@
 //@ dont-require-annotations: NOTE
+//@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
 
 type Field1 = i32;
 type Field2 = f32;
diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr
index 07ff4c3ca36..1843ce273ac 100644
--- a/tests/ui/consts/const-eval/union-const-eval-field.stderr
+++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr
@@ -1,17 +1,21 @@
-error[E0080]: using uninitialized data, but this operation requires initialized memory
-  --> $DIR/union-const-eval-field.rs:28:37
+error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
+  --> $DIR/union-const-eval-field.rs:29:37
    |
 LL |     const FIELD3: Field3 = unsafe { UNION.field3 };
    |                                     ^^^^^^^^^^^^ evaluation of `read_field3::FIELD3` failed here
+   |
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               00 00 80 3f __ __ __ __                         │ ...?░░░░
+           }
 
 note: erroneous constant encountered
-  --> $DIR/union-const-eval-field.rs:30:5
+  --> $DIR/union-const-eval-field.rs:31:5
    |
 LL |     FIELD3
    |     ^^^^^^
 
 note: erroneous constant encountered
-  --> $DIR/union-const-eval-field.rs:30:5
+  --> $DIR/union-const-eval-field.rs:31:5
    |
 LL |     FIELD3
    |     ^^^^^^
diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr
index b00fcc91d68..0506be63ea6 100644
--- a/tests/ui/consts/const-eval/union-ice.stderr
+++ b/tests/ui/consts/const-eval/union-ice.stderr
@@ -1,20 +1,32 @@
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
   --> $DIR/union-ice.rs:14:33
    |
 LL | const FIELD3: Field3 = unsafe { UNION.field3 };
    |                                 ^^^^^^^^^^^^ evaluation of `FIELD3` failed here
+   |
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 80 3f __ __ __ __                         │ ...?░░░░
+           }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC1[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
   --> $DIR/union-ice.rs:19:17
    |
 LL |     b: unsafe { UNION.field3 },
    |                 ^^^^^^^^^^^^ evaluation of `FIELD_PATH` failed here
+   |
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 80 3f __ __ __ __                         │ ...?░░░░
+           }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC2[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
   --> $DIR/union-ice.rs:31:18
    |
 LL |         unsafe { UNION.field3 },
    |                  ^^^^^^^^^^^^ evaluation of `FIELD_PATH2` failed here
+   |
+   = note: the raw bytes of the constant (size: 8, align: 8) {
+               00 00 80 3f __ __ __ __                         │ ...?░░░░
+           }
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr
index 9f0697984e4..757bcea91c3 100644
--- a/tests/ui/consts/const-eval/union-ub.32bit.stderr
+++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr
@@ -9,11 +9,15 @@ LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool };
                2a                                              │ *
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
   --> $DIR/union-ub.rs:35:36
    |
 LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool };
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_BOOL` failed here
+   |
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               __                                              │ ░
+           }
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr
index 9f0697984e4..757bcea91c3 100644
--- a/tests/ui/consts/const-eval/union-ub.64bit.stderr
+++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr
@@ -9,11 +9,15 @@ LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool };
                2a                                              │ *
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
   --> $DIR/union-ub.rs:35:36
    |
 LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool };
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_BOOL` failed here
+   |
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               __                                              │ ░
+           }
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/contracts/contract-attributes-generics.rs b/tests/ui/contracts/contract-attributes-generics.rs
index fd79c6abedd..3763ce116f8 100644
--- a/tests/ui/contracts/contract-attributes-generics.rs
+++ b/tests/ui/contracts/contract-attributes-generics.rs
@@ -5,9 +5,9 @@
 //@ [unchk_pass] run-pass
 //@ [chk_pass] run-pass
 //
-//@ [chk_fail_pre] run-fail
-//@ [chk_fail_post] run-fail
-//@ [chk_const_fail] run-fail
+//@ [chk_fail_pre] run-crash
+//@ [chk_fail_post] run-crash
+//@ [chk_const_fail] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //
diff --git a/tests/ui/contracts/contract-attributes-nest.rs b/tests/ui/contracts/contract-attributes-nest.rs
index e1e61b88f28..d367687b84e 100644
--- a/tests/ui/contracts/contract-attributes-nest.rs
+++ b/tests/ui/contracts/contract-attributes-nest.rs
@@ -5,8 +5,8 @@
 //@ [unchk_fail_post] run-pass
 //@ [chk_pass] run-pass
 //
-//@ [chk_fail_pre] run-fail
-//@ [chk_fail_post] run-fail
+//@ [chk_fail_pre] run-crash
+//@ [chk_fail_post] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
diff --git a/tests/ui/contracts/contract-attributes-tail.rs b/tests/ui/contracts/contract-attributes-tail.rs
index ce4a6be5b82..43edfe5e803 100644
--- a/tests/ui/contracts/contract-attributes-tail.rs
+++ b/tests/ui/contracts/contract-attributes-tail.rs
@@ -5,8 +5,8 @@
 //@ [unchk_fail_post] run-pass
 //@ [chk_pass] run-pass
 //
-//@ [chk_fail_pre] run-fail
-//@ [chk_fail_post] run-fail
+//@ [chk_fail_pre] run-crash
+//@ [chk_fail_post] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
diff --git a/tests/ui/contracts/contract-captures-via-closure-copy.rs b/tests/ui/contracts/contract-captures-via-closure-copy.rs
index 32c6d2bf4fe..bc7e5b9b6f1 100644
--- a/tests/ui/contracts/contract-captures-via-closure-copy.rs
+++ b/tests/ui/contracts/contract-captures-via-closure-copy.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Zcontract-checks=yes
 
 #![feature(contracts)]
diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs
index 733a06ae570..fe8dd37b1f5 100644
--- a/tests/ui/contracts/contract-const-fn.rs
+++ b/tests/ui/contracts/contract-const-fn.rs
@@ -8,8 +8,8 @@
 //
 //@ [all_pass] run-pass
 //
-//@ [runtime_fail_pre] run-fail
-//@ [runtime_fail_post] run-fail
+//@ [runtime_fail_pre] run-crash
+//@ [runtime_fail_post] run-crash
 //
 //@ [all_pass] compile-flags: -Zcontract-checks=yes
 //@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes
diff --git a/tests/ui/contracts/contracts-ensures-early-fn-exit.rs b/tests/ui/contracts/contracts-ensures-early-fn-exit.rs
index 034cead3b4e..44ae07d8c95 100644
--- a/tests/ui/contracts/contracts-ensures-early-fn-exit.rs
+++ b/tests/ui/contracts/contracts-ensures-early-fn-exit.rs
@@ -2,9 +2,9 @@
 //
 //@ [unchk_pass] run-pass
 //@ [chk_pass] run-pass
-//@ [chk_fail_try] run-fail
-//@ [chk_fail_ret] run-fail
-//@ [chk_fail_yeet] run-fail
+//@ [chk_fail_try] run-crash
+//@ [chk_fail_ret] run-crash
+//@ [chk_fail_yeet] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [chk_pass] compile-flags: -Zcontract-checks=yes
diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs
index 6d8cd3949ee..4da0480f8bc 100644
--- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs
+++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs
@@ -5,8 +5,8 @@
 //@ [unchk_fail_post] run-pass
 //@ [chk_pass] run-pass
 //
-//@ [chk_fail_pre] run-fail
-//@ [chk_fail_post] run-fail
+//@ [chk_fail_pre] run-crash
+//@ [chk_fail_post] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs
index 07ec26f921b..f3cf5ce082c 100644
--- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs
+++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs
@@ -5,8 +5,8 @@
 //@ [unchk_fail_post] run-pass
 //@ [chk_pass] run-pass
 //
-//@ [chk_fail_pre] run-fail
-//@ [chk_fail_post] run-fail
+//@ [chk_fail_pre] run-crash
+//@ [chk_fail_post] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
index c62b8cca75a..6e613b53fc9 100644
--- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
+++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
@@ -3,8 +3,8 @@
 //@ [default] run-pass
 //@ [unchk_pass] run-pass
 //@ [chk_pass] run-pass
-//@ [chk_fail_requires] run-fail
-//@ [chk_fail_ensures] run-fail
+//@ [chk_fail_requires] run-crash
+//@ [chk_fail_ensures] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [chk_pass] compile-flags: -Zcontract-checks=yes
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs
index 73c59194531..ac72d233bf6 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs
+++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs
@@ -4,7 +4,7 @@
 //@ [unchk_fail_post] run-pass
 //@ [chk_pass] run-pass
 //
-//@ [chk_fail_post] run-fail
+//@ [chk_fail_post] run-crash
 //
 //@ [unchk_pass] compile-flags: -Zcontract-checks=no
 //@ [unchk_fail_post] compile-flags: -Zcontract-checks=no
diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs
index 75f3eab3e27..035f063cd50 100644
--- a/tests/ui/extern/extern-types-field-offset.rs
+++ b/tests/ui/extern/extern-types-field-offset.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ check-run-results
 //@ exec-env:RUST_BACKTRACE=0
 //@ normalize-stderr: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs
index 6a832744e3e..9c727ae3aad 100644
--- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs
+++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs
@@ -2,23 +2,13 @@
 
 trait Trait1 {}
 auto trait Trait2 {}
-trait Trait3: ?Trait1 {}
-//~^  ERROR `?Trait` is not permitted in supertraits
-trait Trait4 where Self: ?Trait1 {}
-//~^ ERROR ?Trait` bounds are only permitted at the point where a type parameter is declared
+trait Trait3: ?Trait1 {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
+trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitted here
 
 fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
-//~^  ERROR `?Trait` is not permitted in trait object types
+//~^  ERROR relaxed bounds are not permitted in trait object types
 fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-
-trait Trait {}
-// Do not suggest `#![feature(more_maybe_bounds)]` for repetitions
-fn baz<T: ?Trait + ?Trait>(_ : T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr
index 729df4eb37c..da6ad5f16e2 100644
--- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr
+++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr
@@ -1,71 +1,34 @@
-error[E0658]: `?Trait` is not permitted in supertraits
+error: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/feature-gate-more-maybe-bounds.rs:5:15
    |
 LL | trait Trait3: ?Trait1 {}
    |               ^^^^^^^
-   |
-   = note: traits are `?Trait1` by default
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/feature-gate-more-maybe-bounds.rs:10:28
-   |
-LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
-   |                            ^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/feature-gate-more-maybe-bounds.rs:7:26
+error: this relaxed bound is not permitted here
+  --> $DIR/feature-gate-more-maybe-bounds.rs:6:26
    |
 LL | trait Trait4 where Self: ?Trait1 {}
    |                          ^^^^^^^
    |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/feature-gate-more-maybe-bounds.rs:12:11
-   |
-LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
-   |           ^^^^^^^   ^^^^^^^
+error: relaxed bounds are not permitted in trait object types
+  --> $DIR/feature-gate-more-maybe-bounds.rs:8:28
    |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+LL | fn foo(_: Box<dyn Trait1 + ?Trait2>) {}
+   |                            ^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:12:11
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/feature-gate-more-maybe-bounds.rs:10:11
    |
 LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
    |           ^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:12:21
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/feature-gate-more-maybe-bounds.rs:10:21
    |
 LL | fn bar<T: ?Trait1 + ?Trait2>(_: T) {}
    |                     ^^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/feature-gate-more-maybe-bounds.rs:19:11
-   |
-LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
-   |           ^^^^^^   ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:19:11
-   |
-LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
-   |           ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/feature-gate-more-maybe-bounds.rs:19:20
-   |
-LL | fn baz<T: ?Trait + ?Trait>(_ : T) {}
-   |                    ^^^^^^
-
-error: aborting due to 9 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0203, E0658.
-For more information about an error, try `rustc --explain E0203`.
diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs
index 27c493a13bf..7e0e1eadf9c 100644
--- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs
+++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs
@@ -3,8 +3,8 @@
 
 use std::future::Future;
 fn foo() -> impl ?Future<Output = impl Send> {
-    //~^ ERROR: relaxing a default bound only does something for `?Sized`
-    //~| ERROR: relaxing a default bound only does something for `?Sized`
+    //~^ ERROR: bound modifier `?` can only be applied to `Sized`
+    //~| ERROR: bound modifier `?` can only be applied to `Sized`
     ()
 }
 
diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr
index dc4314c58ad..f99d6a7e5f6 100644
--- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr
+++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr
@@ -1,10 +1,10 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/opt-out-bound-not-satisfied.rs:5:18
    |
 LL | fn foo() -> impl ?Future<Output = impl Send> {
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/opt-out-bound-not-satisfied.rs:5:18
    |
 LL | fn foo() -> impl ?Future<Output = impl Send> {
diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr
index 10f4d8d1a71..5f4ef14d586 100644
--- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr
+++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr
@@ -3,6 +3,10 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at
    |
 LL |     std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PADDING` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 2) {
+               01 __ 02 00                                     │ .░..
+           }
 
 error[E0080]: unable to turn pointer into integer
   --> $DIR/intrinsic-raw_eq-const-bad.rs:9:5
diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs
index 09d60b7786b..63f6479ae2e 100644
--- a/tests/ui/issues/issue-37534.rs
+++ b/tests/ui/issues/issue-37534.rs
@@ -1,5 +1,5 @@
 struct Foo<T: ?Hash> {}
 //~^ ERROR expected trait, found derive macro `Hash`
-//~| ERROR relaxing a default bound only does something for `?Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
 
 fn main() {}
diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr
index 3219854bc70..08607354203 100644
--- a/tests/ui/issues/issue-37534.stderr
+++ b/tests/ui/issues/issue-37534.stderr
@@ -9,7 +9,7 @@ help: consider importing this trait instead
 LL + use std::hash::Hash;
    |
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-37534.rs:1:15
    |
 LL | struct Foo<T: ?Hash> {}
diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs
index 4e4e35c6a71..dd9dfc74ca3 100644
--- a/tests/ui/issues/issue-87199.rs
+++ b/tests/ui/issues/issue-87199.rs
@@ -6,12 +6,12 @@
 
 // Check that these function definitions only emit warnings, not errors
 fn arg<T: ?Send>(_: T) {}
-//~^ ERROR: relaxing a default bound only does something for `?Sized`
+//~^ ERROR: bound modifier `?` can only be applied to `Sized`
 fn ref_arg<T: ?Send>(_: &T) {}
-//~^ ERROR: relaxing a default bound only does something for `?Sized`
+//~^ ERROR: bound modifier `?` can only be applied to `Sized`
 fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
-//~^ ERROR: relaxing a default bound only does something for `?Sized`
-//~| ERROR: relaxing a default bound only does something for `?Sized`
+//~^ ERROR: bound modifier `?` can only be applied to `Sized`
+//~| ERROR: bound modifier `?` can only be applied to `Sized`
 
 // Check that there's no `?Sized` relaxation!
 fn main() {
diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr
index acc4e84779c..8a930a3d704 100644
--- a/tests/ui/issues/issue-87199.stderr
+++ b/tests/ui/issues/issue-87199.stderr
@@ -1,22 +1,22 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:8:11
    |
 LL | fn arg<T: ?Send>(_: T) {}
    |           ^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:10:15
    |
 LL | fn ref_arg<T: ?Send>(_: &T) {}
    |               ^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:12:40
    |
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
    |                                        ^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/issue-87199.rs:12:40
    |
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
diff --git a/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs b/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs
index a22965ce1d8..6ba895f172d 100644
--- a/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs
+++ b/tests/ui/mir/alignment/borrow_misaligned_field_projection.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ ignore-i686-pc-windows-msvc: #112480
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
diff --git a/tests/ui/mir/alignment/misaligned_borrow.rs b/tests/ui/mir/alignment/misaligned_borrow.rs
index de8912c7038..60c21deaba5 100644
--- a/tests/ui/mir/alignment/misaligned_borrow.rs
+++ b/tests/ui/mir/alignment/misaligned_borrow.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ ignore-i686-pc-windows-msvc: #112480
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
diff --git a/tests/ui/mir/alignment/misaligned_lhs.rs b/tests/ui/mir/alignment/misaligned_lhs.rs
index b169823bc08..e8ddb10fd9c 100644
--- a/tests/ui/mir/alignment/misaligned_lhs.rs
+++ b/tests/ui/mir/alignment/misaligned_lhs.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ ignore-i686-pc-windows-msvc: #112480
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
diff --git a/tests/ui/mir/alignment/misaligned_mut_borrow.rs b/tests/ui/mir/alignment/misaligned_mut_borrow.rs
index bba20edecfd..c066cc0efcd 100644
--- a/tests/ui/mir/alignment/misaligned_mut_borrow.rs
+++ b/tests/ui/mir/alignment/misaligned_mut_borrow.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ ignore-i686-pc-windows-msvc: #112480
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
diff --git a/tests/ui/mir/alignment/misaligned_rhs.rs b/tests/ui/mir/alignment/misaligned_rhs.rs
index 55da30a2fd7..6bdc39c9d91 100644
--- a/tests/ui/mir/alignment/misaligned_rhs.rs
+++ b/tests/ui/mir/alignment/misaligned_rhs.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ ignore-i686-pc-windows-msvc: #112480
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
diff --git a/tests/ui/mir/alignment/two_pointers.rs b/tests/ui/mir/alignment/two_pointers.rs
index 198a1c9853d..fd8b2f543aa 100644
--- a/tests/ui/mir/alignment/two_pointers.rs
+++ b/tests/ui/mir/alignment/two_pointers.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ ignore-i686-pc-windows-msvc: #112480
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
diff --git a/tests/ui/mir/enum/convert_non_integer_break.rs b/tests/ui/mir/enum/convert_non_integer_break.rs
index 29795190bf6..b0778e2024f 100644
--- a/tests/ui/mir/enum/convert_non_integer_break.rs
+++ b/tests/ui/mir/enum/convert_non_integer_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value
 
diff --git a/tests/ui/mir/enum/convert_non_integer_niche_break.rs b/tests/ui/mir/enum/convert_non_integer_niche_break.rs
index 9ff4849c5b1..d26a3aeb506 100644
--- a/tests/ui/mir/enum/convert_non_integer_niche_break.rs
+++ b/tests/ui/mir/enum/convert_non_integer_niche_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0x5
 
diff --git a/tests/ui/mir/enum/negative_discr_break.rs b/tests/ui/mir/enum/negative_discr_break.rs
index fa1284f72a0..35ee8aa3fc8 100644
--- a/tests/ui/mir/enum/negative_discr_break.rs
+++ b/tests/ui/mir/enum/negative_discr_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0xfd
 
diff --git a/tests/ui/mir/enum/niche_option_tuple_break.rs b/tests/ui/mir/enum/niche_option_tuple_break.rs
index affdc4784a3..0a933afa153 100644
--- a/tests/ui/mir/enum/niche_option_tuple_break.rs
+++ b/tests/ui/mir/enum/niche_option_tuple_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value
 
diff --git a/tests/ui/mir/enum/numbered_variants_break.rs b/tests/ui/mir/enum/numbered_variants_break.rs
index e3e71dc8aec..fbe7d6627a3 100644
--- a/tests/ui/mir/enum/numbered_variants_break.rs
+++ b/tests/ui/mir/enum/numbered_variants_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0x3
 
diff --git a/tests/ui/mir/enum/option_with_bigger_niche_break.rs b/tests/ui/mir/enum/option_with_bigger_niche_break.rs
index c66614b845b..675d27f0ec2 100644
--- a/tests/ui/mir/enum/option_with_bigger_niche_break.rs
+++ b/tests/ui/mir/enum/option_with_bigger_niche_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0x0
 
diff --git a/tests/ui/mir/enum/plain_no_data_break.rs b/tests/ui/mir/enum/plain_no_data_break.rs
index db68e752479..966dd641873 100644
--- a/tests/ui/mir/enum/plain_no_data_break.rs
+++ b/tests/ui/mir/enum/plain_no_data_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0x1
 
diff --git a/tests/ui/mir/enum/single_with_repr_break.rs b/tests/ui/mir/enum/single_with_repr_break.rs
index 5a4ec85a9b5..53e4932d5fd 100644
--- a/tests/ui/mir/enum/single_with_repr_break.rs
+++ b/tests/ui/mir/enum/single_with_repr_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0x1
 
diff --git a/tests/ui/mir/enum/with_niche_int_break.rs b/tests/ui/mir/enum/with_niche_int_break.rs
index 6a97eaa8f4f..d363dc7568a 100644
--- a/tests/ui/mir/enum/with_niche_int_break.rs
+++ b/tests/ui/mir/enum/with_niche_int_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value
 
diff --git a/tests/ui/mir/enum/wrap_break.rs b/tests/ui/mir/enum/wrap_break.rs
index 4491394ca5a..5c410afa511 100644
--- a/tests/ui/mir/enum/wrap_break.rs
+++ b/tests/ui/mir/enum/wrap_break.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: trying to construct an enum from an invalid value 0x0
 #![feature(never_type)]
diff --git a/tests/ui/mir/null/borrowed_mut_null.rs b/tests/ui/mir/null/borrowed_mut_null.rs
index d26452b9dac..a4660f4bf57 100644
--- a/tests/ui/mir/null/borrowed_mut_null.rs
+++ b/tests/ui/mir/null/borrowed_mut_null.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: null pointer dereference occurred
 
diff --git a/tests/ui/mir/null/borrowed_null.rs b/tests/ui/mir/null/borrowed_null.rs
index fefac3a7212..2a50058a482 100644
--- a/tests/ui/mir/null/borrowed_null.rs
+++ b/tests/ui/mir/null/borrowed_null.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: null pointer dereference occurred
 
diff --git a/tests/ui/mir/null/borrowed_null_zst.rs b/tests/ui/mir/null/borrowed_null_zst.rs
index 835727c068b..106fa00b1db 100644
--- a/tests/ui/mir/null/borrowed_null_zst.rs
+++ b/tests/ui/mir/null/borrowed_null_zst.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: null pointer dereference occurred
 
diff --git a/tests/ui/mir/null/null_lhs.rs b/tests/ui/mir/null/null_lhs.rs
index 238d350d1bd..b59338588a5 100644
--- a/tests/ui/mir/null/null_lhs.rs
+++ b/tests/ui/mir/null/null_lhs.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: null pointer dereference occurred
 
diff --git a/tests/ui/mir/null/null_rhs.rs b/tests/ui/mir/null/null_rhs.rs
index 18eafb61869..18fdad759fd 100644
--- a/tests/ui/mir/null/null_rhs.rs
+++ b/tests/ui/mir/null/null_rhs.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: null pointer dereference occurred
 
diff --git a/tests/ui/mir/null/two_pointers.rs b/tests/ui/mir/null/two_pointers.rs
index 52b9510be12..b2aa7cf0384 100644
--- a/tests/ui/mir/null/two_pointers.rs
+++ b/tests/ui/mir/null/two_pointers.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -C debug-assertions
 //@ error-pattern: null pointer dereference occurred
 
diff --git a/tests/ui/panics/panic-in-cleanup.rs b/tests/ui/panics/panic-in-cleanup.rs
index 8cddeb37348..2e307de4393 100644
--- a/tests/ui/panics/panic-in-cleanup.rs
+++ b/tests/ui/panics/panic-in-cleanup.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ exec-env:RUST_BACKTRACE=0
 //@ check-run-results
 //@ error-pattern: panic in a destructor during cleanup
diff --git a/tests/ui/panics/panic-in-ffi.rs b/tests/ui/panics/panic-in-ffi.rs
index 6068e4fdc59..b926d0fa776 100644
--- a/tests/ui/panics/panic-in-ffi.rs
+++ b/tests/ui/panics/panic-in-ffi.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ exec-env:RUST_BACKTRACE=0
 //@ check-run-results
 //@ error-pattern: panic in a function that cannot unwind
diff --git a/tests/ui/panics/panic-in-message-fmt.rs b/tests/ui/panics/panic-in-message-fmt.rs
index 1e9bbaf45c5..4d539f17a0a 100644
--- a/tests/ui/panics/panic-in-message-fmt.rs
+++ b/tests/ui/panics/panic-in-message-fmt.rs
@@ -1,6 +1,6 @@
 // Checks what happens when formatting the panic message panics.
 
-//@ run-fail
+//@ run-crash
 //@ exec-env:RUST_BACKTRACE=0
 //@ check-run-results
 //@ error-pattern: panicked while processing panic
diff --git a/tests/ui/panics/panic-main.rs b/tests/ui/panics/panic-main.rs
index bf79de78a57..2009f69e19e 100644
--- a/tests/ui/panics/panic-main.rs
+++ b/tests/ui/panics/panic-main.rs
@@ -1,27 +1,37 @@
 //@ revisions: default abort-zero abort-one abort-full unwind-zero unwind-one unwind-full
 
+//@[default] run-fail
+
 //@[abort-zero] compile-flags: -Cpanic=abort
 //@[abort-zero] no-prefer-dynamic
 //@[abort-zero] exec-env:RUST_BACKTRACE=0
+//@[abort-zero] run-crash
 
 //@[abort-one] compile-flags: -Cpanic=abort
 //@[abort-one] no-prefer-dynamic
 //@[abort-one] exec-env:RUST_BACKTRACE=1
+//@[abort-one] run-crash
 
 //@[abort-full] compile-flags: -Cpanic=abort
 //@[abort-full] no-prefer-dynamic
 //@[abort-full] exec-env:RUST_BACKTRACE=full
+//@[abort-full] run-crash
 
 //@[unwind-zero] compile-flags: -Cpanic=unwind
 //@[unwind-zero] exec-env:RUST_BACKTRACE=0
+//@[unwind-zero] needs-unwind
+//@[unwind-zero] run-fail
 
 //@[unwind-one] compile-flags: -Cpanic=unwind
 //@[unwind-one] exec-env:RUST_BACKTRACE=1
+//@[unwind-one] needs-unwind
+//@[unwind-one] run-fail
 
 //@[unwind-full] compile-flags: -Cpanic=unwind
 //@[unwind-full] exec-env:RUST_BACKTRACE=full
+//@[unwind-full] needs-unwind
+//@[unwind-full] run-fail
 
-//@ run-fail
 //@ error-pattern:moop
 //@ needs-subprocess
 
diff --git a/tests/ui/parser/deli-ident-issue-2.rs b/tests/ui/parser/deli-ident-issue-2.rs
index 5394760df70..419933c68ad 100644
--- a/tests/ui/parser/deli-ident-issue-2.rs
+++ b/tests/ui/parser/deli-ident-issue-2.rs
@@ -1,6 +1,6 @@
 fn main() {
     if 1 < 2 {
-        let _a = vec!]; //~ ERROR mismatched closing delimiter
+        let _a = vec!];
     }
 } //~ ERROR unexpected closing delimiter
 
diff --git a/tests/ui/parser/deli-ident-issue-2.stderr b/tests/ui/parser/deli-ident-issue-2.stderr
index e0188cdfb4a..703cbf19626 100644
--- a/tests/ui/parser/deli-ident-issue-2.stderr
+++ b/tests/ui/parser/deli-ident-issue-2.stderr
@@ -1,19 +1,13 @@
-error: mismatched closing delimiter: `]`
-  --> $DIR/deli-ident-issue-2.rs:2:14
-   |
-LL |     if 1 < 2 {
-   |              ^ unclosed delimiter
-LL |         let _a = vec!];
-   |                      ^ mismatched closing delimiter
-
 error: unexpected closing delimiter: `}`
   --> $DIR/deli-ident-issue-2.rs:5:1
    |
+LL |     if 1 < 2 {
+   |              - the nearest open delimiter
 LL |         let _a = vec!];
    |                      - missing open `[` for this delimiter
 LL |     }
 LL | }
    | ^ unexpected closing delimiter
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-104367.stderr b/tests/ui/parser/issues/issue-104367.stderr
index c067d12e2d9..f01fa4a1265 100644
--- a/tests/ui/parser/issues/issue-104367.stderr
+++ b/tests/ui/parser/issues/issue-104367.stderr
@@ -18,7 +18,6 @@ LL |     d: [u32; {
 LL |         #![cfg] {
    |                 - unclosed delimiter
 LL |             #![w,)
-   |                  - missing open `(` for this delimiter
 LL |
    |                                                                      ^
 
diff --git a/tests/ui/parser/issues/issue-105209.rs b/tests/ui/parser/issues/issue-105209.rs
index f4e331523bf..12c902e1d80 100644
--- a/tests/ui/parser/issues/issue-105209.rs
+++ b/tests/ui/parser/issues/issue-105209.rs
@@ -1,3 +1,3 @@
 //@ compile-flags: -Zunpretty=ast-tree
 #![c={#![c[)x   //~ ERROR mismatched closing delimiter
-                //~ ERROR this file contains an unclosed delimiter
+    //~ ERROR this file contains an unclosed delimiter
diff --git a/tests/ui/parser/issues/issue-105209.stderr b/tests/ui/parser/issues/issue-105209.stderr
index 72017e4327d..75643d18029 100644
--- a/tests/ui/parser/issues/issue-105209.stderr
+++ b/tests/ui/parser/issues/issue-105209.stderr
@@ -7,16 +7,15 @@ LL | #![c={#![c[)x
    |           unclosed delimiter
 
 error: this file contains an unclosed delimiter
-  --> $DIR/issue-105209.rs:3:68
+  --> $DIR/issue-105209.rs:3:56
    |
 LL | #![c={#![c[)x
-   |   -  -  -  - missing open `(` for this delimiter
-   |   |  |  |
-   |   |  |  unclosed delimiter
+   |   -  -  - unclosed delimiter
+   |   |  |
    |   |  unclosed delimiter
    |   unclosed delimiter
 LL |
-   |                                                                   ^
+   |                                                       ^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-62973.stderr b/tests/ui/parser/issues/issue-62973.stderr
index ea3e2bebee4..c7fc5bc29ed 100644
--- a/tests/ui/parser/issues/issue-62973.stderr
+++ b/tests/ui/parser/issues/issue-62973.stderr
@@ -18,10 +18,8 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-62973.rs:10:2
    |
 LL | fn p() { match s { v, E { [) {) }
-   |        -         -         -  - missing open `(` for this delimiter
-   |        |         |         |
-   |        |         |         missing open `(` for this delimiter
-   |        |         unclosed delimiter
+   |        -         - unclosed delimiter
+   |        |
    |        unclosed delimiter
 LL |
 LL |
diff --git a/tests/ui/parser/issues/issue-63116.stderr b/tests/ui/parser/issues/issue-63116.stderr
index e5bad84d112..736a0ac2cf6 100644
--- a/tests/ui/parser/issues/issue-63116.stderr
+++ b/tests/ui/parser/issues/issue-63116.stderr
@@ -10,9 +10,8 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-63116.rs:4:18
    |
 LL | impl W <s(f;Y(;]
-   |          -     -^
-   |          |     |
-   |          |     missing open `[` for this delimiter
+   |          -      ^
+   |          |
    |          unclosed delimiter
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr b/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
index b82b0f3255b..5301d43e2ae 100644
--- a/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
+++ b/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr
@@ -28,18 +28,14 @@ LL |         V = [Vec::new; { [0].len() ].len() as isize,
 error: this file contains an unclosed delimiter
   --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:23:65
    |
-LL |         V = [PhantomData; { [ () ].len() ].len() as isize,
-   |                                          - missing open `[` for this delimiter
-...
-LL |         V = [Vec::new; { [].len()  ].len() as isize,
-   |                                    - missing open `[` for this delimiter
-...
 LL | mod c {
    |       - unclosed delimiter
 LL |     enum Bug {
-LL |         V = [Vec::new; { [0].len() ].len() as isize,
-   |                                    - missing open `[` for this delimiter
+   |              - this delimiter might not be properly closed...
 ...
+LL | }
+   | - ...as it matches this but it has different indentation
+LL |
 LL | fn main() {}
    |                                                                ^
 
diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs
index 89aaa68ba40..9b4452ed2a1 100644
--- a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs
+++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs
@@ -1,7 +1,7 @@
 // FIXME: this case need more work to fix
 // currently the TokenTree matching ')' with '{', which is not user friendly for diagnostics
 async fn obstest() -> Result<> {
-    let obs_connect = || -> Result<(), MyError) { //~ ERROR mismatched closing delimiter
+    let obs_connect = || -> Result<(), MyError) {
         async {
         }
     }
diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr
index 0ecb748a0a4..c29a4ff8dbe 100644
--- a/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr
+++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr
@@ -1,19 +1,13 @@
-error: mismatched closing delimiter: `)`
-  --> $DIR/issue-68987-unmatch-issue-2.rs:3:32
-   |
-LL | async fn obstest() -> Result<> {
-   |                                ^ unclosed delimiter
-LL |     let obs_connect = || -> Result<(), MyError) {
-   |                                               ^ mismatched closing delimiter
-
 error: unexpected closing delimiter: `}`
   --> $DIR/issue-68987-unmatch-issue-2.rs:14:1
    |
+LL | async fn obstest() -> Result<> {
+   |                                - the nearest open delimiter
 LL |     let obs_connect = || -> Result<(), MyError) {
    |                                               - missing open `(` for this delimiter
 ...
 LL | }
    | ^ unexpected closing delimiter
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs
index e98df8d7c3c..e71e2730980 100644
--- a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs
+++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs
@@ -3,6 +3,6 @@ fn f(i: u32, j: u32) {
     let res = String::new();
     let mut cnt = i;
     while cnt < j {
-        write!&mut res, " "); //~ ERROR mismatched closing delimiter
+        write!&mut res, " ");
     }
 } //~ ERROR unexpected closing delimiter
diff --git a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr
index dfc4407ed65..6b012af1af3 100644
--- a/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr
+++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr
@@ -1,19 +1,13 @@
-error: mismatched closing delimiter: `)`
-  --> $DIR/issue-68987-unmatch-issue-3.rs:5:19
-   |
-LL |     while cnt < j {
-   |                   ^ unclosed delimiter
-LL |         write!&mut res, " ");
-   |                            ^ mismatched closing delimiter
-
 error: unexpected closing delimiter: `}`
   --> $DIR/issue-68987-unmatch-issue-3.rs:8:1
    |
+LL |     while cnt < j {
+   |                   - the nearest open delimiter
 LL |         write!&mut res, " ");
    |                            - missing open `(` for this delimiter
 LL |     }
 LL | }
    | ^ unexpected closing delimiter
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-81827.stderr b/tests/ui/parser/issues/issue-81827.stderr
index 986ed6b7e70..9737c8c90ae 100644
--- a/tests/ui/parser/issues/issue-81827.stderr
+++ b/tests/ui/parser/issues/issue-81827.stderr
@@ -11,9 +11,8 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-81827.rs:7:27
    |
 LL | fn r()->i{0|{#[cfg(r(0{]0
-   |          -  -          - ^
-   |          |  |          |
-   |          |  |          missing open `[` for this delimiter
+   |          -  -            ^
+   |          |  |
    |          |  unclosed delimiter
    |          unclosed delimiter
 
diff --git a/tests/ui/parser/issues/unnessary-error-issue-138401.rs b/tests/ui/parser/issues/unnessary-error-issue-138401.rs
new file mode 100644
index 00000000000..208c516365a
--- /dev/null
+++ b/tests/ui/parser/issues/unnessary-error-issue-138401.rs
@@ -0,0 +1,6 @@
+pub fn foo(x: i64) -> i64 {
+    x.abs)
+}
+//~^ ERROR unexpected closing delimiter: `}`
+
+fn main() {}
diff --git a/tests/ui/parser/issues/unnessary-error-issue-138401.stderr b/tests/ui/parser/issues/unnessary-error-issue-138401.stderr
new file mode 100644
index 00000000000..54c73b50a42
--- /dev/null
+++ b/tests/ui/parser/issues/unnessary-error-issue-138401.stderr
@@ -0,0 +1,12 @@
+error: unexpected closing delimiter: `}`
+  --> $DIR/unnessary-error-issue-138401.rs:3:1
+   |
+LL | pub fn foo(x: i64) -> i64 {
+   |                           - the nearest open delimiter
+LL |     x.abs)
+   |          - missing open `(` for this delimiter
+LL | }
+   | ^ unexpected closing delimiter
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/trait-object-trait-parens.rs b/tests/ui/parser/trait-object-trait-parens.rs
index 438034bc38a..51f0e2de611 100644
--- a/tests/ui/parser/trait-object-trait-parens.rs
+++ b/tests/ui/parser/trait-object-trait-parens.rs
@@ -6,17 +6,17 @@ fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
 
 fn main() {
     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
+    //~^ ERROR relaxed bounds are not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
+    //~^ ERROR relaxed bounds are not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
+    //~^ ERROR relaxed bounds are not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition
diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr
index d75352b6811..26d388f8779 100644
--- a/tests/ui/parser/trait-object-trait-parens.stderr
+++ b/tests/ui/parser/trait-object-trait-parens.stderr
@@ -1,29 +1,20 @@
-error[E0658]: `?Trait` is not permitted in trait object types
+error: relaxed bounds are not permitted in trait object types
   --> $DIR/trait-object-trait-parens.rs:8:24
    |
 LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |                        ^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in trait object types
+error: relaxed bounds are not permitted in trait object types
   --> $DIR/trait-object-trait-parens.rs:13:16
    |
 LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
    |                ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in trait object types
+error: relaxed bounds are not permitted in trait object types
   --> $DIR/trait-object-trait-parens.rs:18:44
    |
 LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
    |                                            ^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/trait-object-trait-parens.rs:8:16
@@ -100,5 +91,4 @@ LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
 
 error: aborting due to 6 previous errors; 3 warnings emitted
 
-Some errors have detailed explanations: E0225, E0658.
-For more information about an error, try `rustc --explain E0225`.
+For more information about this error, try `rustc --explain E0225`.
diff --git a/tests/ui/precondition-checks/alignment.rs b/tests/ui/precondition-checks/alignment.rs
index 92400528fa0..038a625bed7 100644
--- a/tests/ui/precondition-checks/alignment.rs
+++ b/tests/ui/precondition-checks/alignment.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: Alignment::new_unchecked requires
 
diff --git a/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs b/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs
index 30c6f79fb08..41ba2c5254a 100644
--- a/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs
+++ b/tests/ui/precondition-checks/ascii-char-digit_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: `ascii::Char::digit_unchecked` input cannot exceed 9
 
diff --git a/tests/ui/precondition-checks/assert_unchecked.rs b/tests/ui/precondition-checks/assert_unchecked.rs
index 22b2b414550..da5383cdea0 100644
--- a/tests/ui/precondition-checks/assert_unchecked.rs
+++ b/tests/ui/precondition-checks/assert_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: hint::assert_unchecked must never be called when the condition is false
 
diff --git a/tests/ui/precondition-checks/char-from_u32_unchecked.rs b/tests/ui/precondition-checks/char-from_u32_unchecked.rs
index d950f20c772..7c34d926d3e 100644
--- a/tests/ui/precondition-checks/char-from_u32_unchecked.rs
+++ b/tests/ui/precondition-checks/char-from_u32_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: invalid value for `char`
 
diff --git a/tests/ui/precondition-checks/copy-nonoverlapping.rs b/tests/ui/precondition-checks/copy-nonoverlapping.rs
index eacaa63e543..1d584ddef4c 100644
--- a/tests/ui/precondition-checks/copy-nonoverlapping.rs
+++ b/tests/ui/precondition-checks/copy-nonoverlapping.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: ptr::copy_nonoverlapping requires
 //@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping
diff --git a/tests/ui/precondition-checks/copy.rs b/tests/ui/precondition-checks/copy.rs
index 1fadd90bf70..8faa56a880e 100644
--- a/tests/ui/precondition-checks/copy.rs
+++ b/tests/ui/precondition-checks/copy.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: ptr::copy requires
 //@ revisions: null_src null_dst misaligned_src misaligned_dst
diff --git a/tests/ui/precondition-checks/layout.rs b/tests/ui/precondition-checks/layout.rs
index 4ee66cc9328..6755ebce854 100644
--- a/tests/ui/precondition-checks/layout.rs
+++ b/tests/ui/precondition-checks/layout.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: Layout::from_size_align_unchecked requires
 //@ revisions: toolarge badalign
diff --git a/tests/ui/precondition-checks/nonnull.rs b/tests/ui/precondition-checks/nonnull.rs
index 6b8edd4e582..75bbd65b486 100644
--- a/tests/ui/precondition-checks/nonnull.rs
+++ b/tests/ui/precondition-checks/nonnull.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: NonNull::new_unchecked requires
 
diff --git a/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs b/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs
index 46ce7dc356f..d55707fdd0b 100644
--- a/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs
+++ b/tests/ui/precondition-checks/nonzero-from_mut_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: NonZero::from_mut_unchecked requires
 
diff --git a/tests/ui/precondition-checks/nonzero-new_unchecked.rs b/tests/ui/precondition-checks/nonzero-new_unchecked.rs
index 7827a42844f..978f01f150f 100644
--- a/tests/ui/precondition-checks/nonzero-new_unchecked.rs
+++ b/tests/ui/precondition-checks/nonzero-new_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: NonZero::new_unchecked requires
 
diff --git a/tests/ui/precondition-checks/read_volatile.rs b/tests/ui/precondition-checks/read_volatile.rs
index ada8932c398..fa1c2c827d7 100644
--- a/tests/ui/precondition-checks/read_volatile.rs
+++ b/tests/ui/precondition-checks/read_volatile.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires
 //@ revisions: null misaligned
diff --git a/tests/ui/precondition-checks/replace.rs b/tests/ui/precondition-checks/replace.rs
index 44afbd8174c..447a00c6572 100644
--- a/tests/ui/precondition-checks/replace.rs
+++ b/tests/ui/precondition-checks/replace.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: ptr::replace requires
 //@ revisions: null misaligned
diff --git a/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs b/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs
index 9b9ded69a83..b6397ab2a12 100644
--- a/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs
+++ b/tests/ui/precondition-checks/slice-from-raw-parts-mut.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts_mut requires
 //@ revisions: null misaligned toolarge
diff --git a/tests/ui/precondition-checks/slice-from-raw-parts.rs b/tests/ui/precondition-checks/slice-from-raw-parts.rs
index 96578c1eae5..a317e3d41a0 100644
--- a/tests/ui/precondition-checks/slice-from-raw-parts.rs
+++ b/tests/ui/precondition-checks/slice-from-raw-parts.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts requires
 //@ revisions: null misaligned toolarge
diff --git a/tests/ui/precondition-checks/slice-get_unchecked.rs b/tests/ui/precondition-checks/slice-get_unchecked.rs
index 1d8188fb953..7bcb8442540 100644
--- a/tests/ui/precondition-checks/slice-get_unchecked.rs
+++ b/tests/ui/precondition-checks/slice-get_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: slice::get_unchecked requires
 //@ revisions: usize range range_to range_from backwards_range
diff --git a/tests/ui/precondition-checks/slice-get_unchecked_mut.rs b/tests/ui/precondition-checks/slice-get_unchecked_mut.rs
index 34c1454af43..2ba3227f39e 100644
--- a/tests/ui/precondition-checks/slice-get_unchecked_mut.rs
+++ b/tests/ui/precondition-checks/slice-get_unchecked_mut.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: slice::get_unchecked_mut requires
 //@ revisions: usize range range_to range_from backwards_range
diff --git a/tests/ui/precondition-checks/str-get_unchecked.rs b/tests/ui/precondition-checks/str-get_unchecked.rs
index 14d17f997ec..2273190e9f4 100644
--- a/tests/ui/precondition-checks/str-get_unchecked.rs
+++ b/tests/ui/precondition-checks/str-get_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: str::get_unchecked requires
 //@ revisions: range range_to range_from backwards_range
diff --git a/tests/ui/precondition-checks/str-get_unchecked_mut.rs b/tests/ui/precondition-checks/str-get_unchecked_mut.rs
index ca1b1690055..53e6ee64d47 100644
--- a/tests/ui/precondition-checks/str-get_unchecked_mut.rs
+++ b/tests/ui/precondition-checks/str-get_unchecked_mut.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: str::get_unchecked_mut requires
 //@ revisions: range range_to range_from backwards_range
diff --git a/tests/ui/precondition-checks/swap-nonoverlapping.rs b/tests/ui/precondition-checks/swap-nonoverlapping.rs
index ea1f6f36ad7..81ba72382c0 100644
--- a/tests/ui/precondition-checks/swap-nonoverlapping.rs
+++ b/tests/ui/precondition-checks/swap-nonoverlapping.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: ptr::swap_nonoverlapping requires
 //@ revisions: null_src null_dst misaligned_src misaligned_dst overlapping
diff --git a/tests/ui/precondition-checks/unchecked_add.rs b/tests/ui/precondition-checks/unchecked_add.rs
index f44a6ea32ad..b7727aeb968 100644
--- a/tests/ui/precondition-checks/unchecked_add.rs
+++ b/tests/ui/precondition-checks/unchecked_add.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_add cannot overflow
 
diff --git a/tests/ui/precondition-checks/unchecked_mul.rs b/tests/ui/precondition-checks/unchecked_mul.rs
index 66655dda136..3eea8b66abb 100644
--- a/tests/ui/precondition-checks/unchecked_mul.rs
+++ b/tests/ui/precondition-checks/unchecked_mul.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_add cannot overflow
 
diff --git a/tests/ui/precondition-checks/unchecked_shl.rs b/tests/ui/precondition-checks/unchecked_shl.rs
index 1c96db0b1ec..57c617e0845 100644
--- a/tests/ui/precondition-checks/unchecked_shl.rs
+++ b/tests/ui/precondition-checks/unchecked_shl.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shl cannot overflow
 
diff --git a/tests/ui/precondition-checks/unchecked_shr.rs b/tests/ui/precondition-checks/unchecked_shr.rs
index 4a6d9ffb1d3..18502d2b645 100644
--- a/tests/ui/precondition-checks/unchecked_shr.rs
+++ b/tests/ui/precondition-checks/unchecked_shr.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shr cannot overflow
 
diff --git a/tests/ui/precondition-checks/unchecked_sub.rs b/tests/ui/precondition-checks/unchecked_sub.rs
index 545dde0e278..bfe8f5849f5 100644
--- a/tests/ui/precondition-checks/unchecked_sub.rs
+++ b/tests/ui/precondition-checks/unchecked_sub.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_sub cannot overflow
 
diff --git a/tests/ui/precondition-checks/unreachable_unchecked.rs b/tests/ui/precondition-checks/unreachable_unchecked.rs
index 2435450c4b5..f2855d03a3e 100644
--- a/tests/ui/precondition-checks/unreachable_unchecked.rs
+++ b/tests/ui/precondition-checks/unreachable_unchecked.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: hint::unreachable_unchecked must never be reached
 
diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs
index 0bafb5aa715..ace90770360 100644
--- a/tests/ui/precondition-checks/vec-from-parts.rs
+++ b/tests/ui/precondition-checks/vec-from-parts.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Cdebug-assertions=yes
 //@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity
 #![feature(allocator_api)]
diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs
index 884d34c0a56..1bc8e6ada10 100644
--- a/tests/ui/precondition-checks/vec-from-raw-parts.rs
+++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Cdebug-assertions=yes
 //@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity
 //@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts
diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs
index 0987e7fe028..c6bdee7dc67 100644
--- a/tests/ui/precondition-checks/vec-set-len.rs
+++ b/tests/ui/precondition-checks/vec-set-len.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Cdebug-assertions=yes
 //@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity()
 
diff --git a/tests/ui/precondition-checks/write_volatile.rs b/tests/ui/precondition-checks/write_volatile.rs
index 0d5ecb014b3..25107871c39 100644
--- a/tests/ui/precondition-checks/write_volatile.rs
+++ b/tests/ui/precondition-checks/write_volatile.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
 //@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires
 //@ revisions: null misaligned
diff --git a/tests/ui/sanitizer/address.rs b/tests/ui/sanitizer/address.rs
index 7a5e767687c..704d84764c1 100644
--- a/tests/ui/sanitizer/address.rs
+++ b/tests/ui/sanitizer/address.rs
@@ -4,7 +4,7 @@
 //
 //@ compile-flags: -Z sanitizer=address -O -g
 //
-//@ run-fail
+//@ run-fail-or-crash
 //@ error-pattern: AddressSanitizer: stack-buffer-overflow
 //@ error-pattern: 'xs' (line 14) <== Memory access at offset
 
diff --git a/tests/ui/sanitizer/badfree.rs b/tests/ui/sanitizer/badfree.rs
index ecbb58eba00..6b3aea7239c 100644
--- a/tests/ui/sanitizer/badfree.rs
+++ b/tests/ui/sanitizer/badfree.rs
@@ -4,7 +4,7 @@
 //
 //@ compile-flags: -Z sanitizer=address -O
 //
-//@ run-fail
+//@ run-fail-or-crash
 //@ regex-error-pattern: AddressSanitizer: (SEGV|attempting free on address which was not malloc)
 
 use std::ffi::c_void;
diff --git a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs
index b7dd4a43782..c1a2c2f26ac 100644
--- a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs
+++ b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs
@@ -11,7 +11,7 @@
 //@ compile-flags: -Zsanitizer=address -Clto=thin
 //@[opt0]compile-flags: -Copt-level=0
 //@[opt1]compile-flags: -Copt-level=1
-//@ run-fail
+//@ run-fail-or-crash
 //@ error-pattern: ERROR: AddressSanitizer: stack-use-after-scope
 
 static mut P: *mut usize = std::ptr::null_mut();
diff --git a/tests/ui/sanitizer/thread.rs b/tests/ui/sanitizer/thread.rs
index 566774d6b1d..9073124d1bd 100644
--- a/tests/ui/sanitizer/thread.rs
+++ b/tests/ui/sanitizer/thread.rs
@@ -15,7 +15,7 @@
 //
 //@ compile-flags: -Z sanitizer=thread -O
 //
-//@ run-fail
+//@ run-fail-or-crash
 //@ error-pattern: WARNING: ThreadSanitizer: data race
 //@ error-pattern: Location is heap block of size 4
 //@ error-pattern: allocated by main thread
diff --git a/tests/ui/sanitizer/use-after-scope.rs b/tests/ui/sanitizer/use-after-scope.rs
index 4d7f6f6c2f2..106dc6466d6 100644
--- a/tests/ui/sanitizer/use-after-scope.rs
+++ b/tests/ui/sanitizer/use-after-scope.rs
@@ -3,7 +3,7 @@
 //@ ignore-cross-compile
 //
 //@ compile-flags: -Zsanitizer=address
-//@ run-fail
+//@ run-fail-or-crash
 //@ error-pattern: ERROR: AddressSanitizer: stack-use-after-scope
 
 static mut P: *mut usize = std::ptr::null_mut();
diff --git a/tests/ui/sized-hierarchy/default-bound.rs b/tests/ui/sized-hierarchy/default-bound.rs
index 12b2eb2b5c1..bbb2c6d96ba 100644
--- a/tests/ui/sized-hierarchy/default-bound.rs
+++ b/tests/ui/sized-hierarchy/default-bound.rs
@@ -14,13 +14,13 @@ fn neg_sized<T: ?Sized>() {}
 fn metasized<T: MetaSized>() {}
 
 fn neg_metasized<T: ?MetaSized>() {}
-//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 
 
 fn pointeesized<T: PointeeSized>() { }
 
 fn neg_pointeesized<T: ?PointeeSized>() { }
-//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 
 
 fn main() {
diff --git a/tests/ui/sized-hierarchy/default-bound.stderr b/tests/ui/sized-hierarchy/default-bound.stderr
index 22f0fa29d3e..0a4ea6f44d8 100644
--- a/tests/ui/sized-hierarchy/default-bound.stderr
+++ b/tests/ui/sized-hierarchy/default-bound.stderr
@@ -1,10 +1,10 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/default-bound.rs:16:21
    |
 LL | fn neg_metasized<T: ?MetaSized>() {}
    |                     ^^^^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/default-bound.rs:22:24
    |
 LL | fn neg_pointeesized<T: ?PointeeSized>() { }
diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs
index b25acf9e6ea..ab3b28e84db 100644
--- a/tests/ui/sized-hierarchy/default-supertrait.rs
+++ b/tests/ui/sized-hierarchy/default-supertrait.rs
@@ -6,18 +6,18 @@ use std::marker::{MetaSized, PointeeSized};
 trait Sized_: Sized { }
 
 trait NegSized: ?Sized { }
-//~^ ERROR `?Trait` is not permitted in supertraits
+//~^ ERROR relaxed bounds are not permitted in supertrait bounds
 
 trait MetaSized_: MetaSized { }
 
 trait NegMetaSized: ?MetaSized { }
-//~^ ERROR `?Trait` is not permitted in supertraits
+//~^ ERROR relaxed bounds are not permitted in supertrait bounds
 
 
 trait PointeeSized_: PointeeSized { }
 
 trait NegPointeeSized: ?PointeeSized { }
-//~^ ERROR `?Trait` is not permitted in supertraits
+//~^ ERROR relaxed bounds are not permitted in supertrait bounds
 
 trait Bare {}
 
diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr
index de23936b900..f5589d6e279 100644
--- a/tests/ui/sized-hierarchy/default-supertrait.stderr
+++ b/tests/ui/sized-hierarchy/default-supertrait.stderr
@@ -1,32 +1,22 @@
-error[E0658]: `?Trait` is not permitted in supertraits
+error: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/default-supertrait.rs:8:17
    |
 LL | trait NegSized: ?Sized { }
    |                 ^^^^^^
    |
    = note: traits are `?Sized` by default
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in supertraits
+error: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/default-supertrait.rs:13:21
    |
 LL | trait NegMetaSized: ?MetaSized { }
    |                     ^^^^^^^^^^
-   |
-   = note: traits are `?MetaSized` by default
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `?Trait` is not permitted in supertraits
+error: relaxed bounds are not permitted in supertrait bounds
   --> $DIR/default-supertrait.rs:19:24
    |
 LL | trait NegPointeeSized: ?PointeeSized { }
    |                        ^^^^^^^^^^^^^
-   |
-   = note: traits are `?PointeeSized` by default
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0277]: the size for values of type `T` cannot be known
   --> $DIR/default-supertrait.rs:52:38
@@ -121,5 +111,4 @@ LL | fn with_bare_trait<T: PointeeSized + Bare + std::marker::MetaSized>() {
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0277, E0658.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/pointee-validation.rs b/tests/ui/sized-hierarchy/pointee-validation.rs
new file mode 100644
index 00000000000..dfc28829e08
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pointee-validation.rs
@@ -0,0 +1,20 @@
+// Test that despite us dropping `PointeeSized` bounds during HIR ty lowering
+// we still validate it first.
+// issue: <https://github.com/rust-lang/rust/issues/142718>
+#![feature(sized_hierarchy)]
+
+use std::marker::PointeeSized;
+
+struct T where (): PointeeSized<(), Undefined = ()>;
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
+//~| ERROR associated type `Undefined` not found for `PointeeSized`
+
+const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+//~^ ERROR `const` can only be applied to `const` traits
+//~| ERROR `const` can only be applied to `const` traits
+//~| ERROR const trait impls are experimental
+//~| ERROR `[const]` can only be applied to `const` traits
+//~| ERROR `[const]` can only be applied to `const` traits
+//~| ERROR const trait impls are experimental
+
+fn main() {}
diff --git a/tests/ui/sized-hierarchy/pointee-validation.stderr b/tests/ui/sized-hierarchy/pointee-validation.stderr
new file mode 100644
index 00000000000..a056d548356
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pointee-validation.stderr
@@ -0,0 +1,76 @@
+error[E0658]: const trait impls are experimental
+  --> $DIR/pointee-validation.rs:12:32
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                ^^^^^
+   |
+   = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/pointee-validation.rs:12:55
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                                       ^^^^^^^
+   |
+   = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/pointee-validation.rs:8:20
+   |
+LL | struct T where (): PointeeSized<(), Undefined = ()>;
+   |                    ^^^^^^^^^^^^-------------------- help: remove the unnecessary generics
+   |                    |
+   |                    expected 0 generic arguments
+
+error[E0220]: associated type `Undefined` not found for `PointeeSized`
+  --> $DIR/pointee-validation.rs:8:37
+   |
+LL | struct T where (): PointeeSized<(), Undefined = ()>;
+   |                                     ^^^^^^^^^ associated type `Undefined` not found
+
+error: `const` can only be applied to `const` traits
+  --> $DIR/pointee-validation.rs:12:32
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                ^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `const` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: `[const]` can only be applied to `const` traits
+  --> $DIR/pointee-validation.rs:12:55
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                                       ^^^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `[const]` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: `const` can only be applied to `const` traits
+  --> $DIR/pointee-validation.rs:12:32
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                ^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `const` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `[const]` can only be applied to `const` traits
+  --> $DIR/pointee-validation.rs:12:55
+   |
+LL | const fn test<T, U>() where T: const PointeeSized, U: [const] PointeeSized {}
+   |                                                       ^^^^^^^ can't be applied to `PointeeSized`
+   |
+note: `PointeeSized` can't be used with `[const]` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0107, E0220, E0658.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
index ece1702679d..89e4c15371d 100644
--- a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
+++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.rs
@@ -3,7 +3,7 @@
 use std::marker::PointeeSized;
 
 type Foo = dyn PointeeSized;
-//~^ ERROR `PointeeSized` cannot be used with trait objects
+//~^ ERROR at least one trait is required for an object type
 
 fn foo(f: &Foo) {}
 
@@ -12,5 +12,5 @@ fn main() {
 
     let x = main;
     let y: Box<dyn PointeeSized> = x;
-//~^ ERROR `PointeeSized` cannot be used with trait objects
+//~^ ERROR at least one trait is required for an object type
 }
diff --git a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
index a833c6952fd..616b2400f86 100644
--- a/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
+++ b/tests/ui/sized-hierarchy/reject-dyn-pointeesized.stderr
@@ -1,10 +1,10 @@
-error: `PointeeSized` cannot be used with trait objects
+error[E0224]: at least one trait is required for an object type
   --> $DIR/reject-dyn-pointeesized.rs:5:12
    |
 LL | type Foo = dyn PointeeSized;
    |            ^^^^^^^^^^^^^^^^
 
-error: `PointeeSized` cannot be used with trait objects
+error[E0224]: at least one trait is required for an object type
   --> $DIR/reject-dyn-pointeesized.rs:14:16
    |
 LL |     let y: Box<dyn PointeeSized> = x;
@@ -12,3 +12,4 @@ LL |     let y: Box<dyn PointeeSized> = x;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/std/issue-81357-unsound-file-methods.rs b/tests/ui/std/issue-81357-unsound-file-methods.rs
index 838df40c32d..99bd31aa260 100644
--- a/tests/ui/std/issue-81357-unsound-file-methods.rs
+++ b/tests/ui/std/issue-81357-unsound-file-methods.rs
@@ -1,4 +1,4 @@
-//@ run-fail
+//@ run-crash
 //@ only-windows
 
 fn main() {
diff --git a/tests/ui/suggestions/issue-94171.stderr b/tests/ui/suggestions/issue-94171.stderr
index bcbd46cd8ec..52306a2465f 100644
--- a/tests/ui/suggestions/issue-94171.stderr
+++ b/tests/ui/suggestions/issue-94171.stderr
@@ -22,9 +22,7 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-94171.rs:5:52
    |
 LL | fn L(]{match
-   |      -- unclosed delimiter
-   |      |
-   |      missing open `[` for this delimiter
+   |       - unclosed delimiter
 LL | (; {`
    | -  - unclosed delimiter
    | |
diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs
new file mode 100644
index 00000000000..a1681ddec77
--- /dev/null
+++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs
@@ -0,0 +1,22 @@
+fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+//~^ ERROR duplicate relaxed `Sized` bounds
+//~| ERROR duplicate relaxed `Iterator` bounds
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+
+trait Trait {
+    // We used to say "type parameter has more than one relaxed default bound"
+    // even on *associated types* like here. Test that we no longer do that.
+    type Type: ?Sized + ?Sized;
+    //~^ ERROR duplicate relaxed `Sized` bounds
+    //~| ERROR duplicate relaxed `Sized` bounds
+}
+
+// We used to emit an additional error about "multiple relaxed default bounds".
+// However, multiple relaxed bounds are actually *fine* if they're distinct.
+// Ultimately, we still reject this because `Sized` is
+// the only (stable) default trait, so we're fine.
+fn not_dupes<T: ?Sized + ?Iterator>() {}
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
+
+fn main() {}
diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr
new file mode 100644
index 00000000000..ccc723fc7a6
--- /dev/null
+++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr
@@ -0,0 +1,47 @@
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:1:13
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |             ^^^^^^   ^^^^^^
+
+error[E0203]: duplicate relaxed `Iterator` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:1:31
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |                               ^^^^^^^^^   ^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/duplicate-relaxed-bounds.rs:1:31
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |                               ^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/duplicate-relaxed-bounds.rs:1:43
+   |
+LL | fn dupes<T: ?Sized + ?Sized + ?Iterator + ?Iterator>() {}
+   |                                           ^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/duplicate-relaxed-bounds.rs:19:26
+   |
+LL | fn not_dupes<T: ?Sized + ?Iterator>() {}
+   |                          ^^^^^^^^^
+
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:10:16
+   |
+LL |     type Type: ?Sized + ?Sized;
+   |                ^^^^^^   ^^^^^^
+
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/duplicate-relaxed-bounds.rs:10:16
+   |
+LL |     type Type: ?Sized + ?Sized;
+   |                ^^^^^^   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0203`.
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs
index e6d7f74880f..1aa36207bc3 100644
--- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
+++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs
@@ -1,39 +1,38 @@
-// Regression test for #127441
-
-// Tests that we make the correct suggestion
-// in case there are more than one `?Sized`
-// bounds on a function parameter
+// Test that we emit a correct structured suggestions for dynamically sized ("maybe unsized")
+// function parameters.
+// We used to emit a butchered suggestion if duplicate relaxed `Sized` bounds were present.
+// issue: <https://github.com/rust-lang/rust/issues/127441>.
 
 use std::fmt::Debug;
 
 fn foo1<T: ?Sized>(a: T) {}
-//~^ ERROR he size for values of type `T` cannot be known at compilation time
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo2<T: ?Sized + ?Sized>(a: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR he size for values of type `T` cannot be known at compilation time
+//~^ ERROR duplicate relaxed `Sized` bounds
+//~| ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `T` cannot be known at compilation time
 
 fn foo5(_: impl ?Sized) {}
 //~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
 
 fn foo6(_: impl ?Sized + ?Sized) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
 
 fn foo7(_: impl ?Sized + ?Sized + Debug) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
 
 fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~^ ERROR duplicate relaxed `Sized` bounds
 //~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr
index 363f52d6df8..7a9c2f043ac 100644
--- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
+++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr
@@ -1,41 +1,41 @@
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:12
    |
 LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
    |            ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:12
    |
 LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
    |            ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:12
    |
 LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
    |            ^^^^^^           ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:17
    |
 LL | fn foo6(_: impl ?Sized + ?Sized) {}
    |                 ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:17
    |
 LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
    |                 ^^^^^^   ^^^^^^
 
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
+error[E0203]: duplicate relaxed `Sized` bounds
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:17
    |
 LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
    |                 ^^^^^^           ^^^^^^
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:23
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:8:23
    |
 LL | fn foo1<T: ?Sized>(a: T) {}
    |         -             ^ doesn't have a size known at compile-time
@@ -54,7 +54,7 @@ LL | fn foo1<T: ?Sized>(a: &T) {}
    |                       +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:32
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:32
    |
 LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
    |         -                      ^ doesn't have a size known at compile-time
@@ -73,7 +73,7 @@ LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
    |                                +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:40
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:40
    |
 LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
    |         -                              ^ doesn't have a size known at compile-time
@@ -92,7 +92,7 @@ LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
    |                                        +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:41
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:41
    |
 LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
    |         -                               ^ doesn't have a size known at compile-time
@@ -111,7 +111,7 @@ LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
    |                                         +
 
 error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:23:12
    |
 LL | fn foo5(_: impl ?Sized) {}
    |            ^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL | fn foo5(_: &impl ?Sized) {}
    |            +
 
 error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:12
    |
 LL | fn foo6(_: impl ?Sized + ?Sized) {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -151,7 +151,7 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {}
    |            +
 
 error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:12
    |
 LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
    |            +
 
 error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
-  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12
+  --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:12
    |
 LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
index e5abcae5d21..14a26670497 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
@@ -2,6 +2,6 @@ trait Trait {}
 
 fn test<T: ?self::<i32>::Trait>() {}
 //~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args`
-//~| ERROR relaxing a default bound only does something for `?Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
index dc55b26c918..bf968b05af0 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
@@ -1,4 +1,4 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/maybe-bound-has-path-args.rs:3:12
    |
 LL | fn test<T: ?self::<i32>::Trait>() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs
index 9127c2de16d..e123f18474d 100644
--- a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs
+++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs
@@ -2,11 +2,11 @@ trait HasAssoc {
     type Assoc;
 }
 fn hasassoc<T: ?HasAssoc<Assoc = ()>>() {}
-//~^ ERROR relaxing a default bound
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 
 trait NoAssoc {}
 fn noassoc<T: ?NoAssoc<Missing = ()>>() {}
-//~^ ERROR relaxing a default bound
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
 //~| ERROR associated type `Missing` not found for `NoAssoc`
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr
index 36a1e0ade20..b2ae0584aff 100644
--- a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr
+++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr
@@ -1,10 +1,10 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/maybe-bound-with-assoc.rs:4:16
    |
 LL | fn hasassoc<T: ?HasAssoc<Assoc = ()>>() {}
    |                ^^^^^^^^^^^^^^^^^^^^^
 
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+error: bound modifier `?` can only be applied to `Sized`
   --> $DIR/maybe-bound-with-assoc.rs:8:15
    |
 LL | fn noassoc<T: ?NoAssoc<Missing = ()>>() {}
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs
new file mode 100644
index 00000000000..47348b0a0dd
--- /dev/null
+++ b/tests/ui/trait-bounds/more_maybe_bounds.rs
@@ -0,0 +1,29 @@
+// FIXME(more_maybe_bounds): Even under `more_maybe_bounds` / `-Zexperimental-default-bounds`,
+// trying to relax non-default bounds should still be an error in all contexts! As you can see
+// there are places like supertrait bounds and trait object types where we currently don't perform
+// this check.
+#![feature(auto_traits, more_maybe_bounds, negative_impls)]
+
+trait Trait1 {}
+auto trait Trait2 {}
+
+// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
+trait Trait3: ?Trait1 {}
+trait Trait4 where Self: Trait1 {}
+
+// FIXME: `?Trait2` should be rejected, `Trait2` isn't marked `#[lang = "default_traitN"]`.
+fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
+fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+//~^ ERROR bound modifier `?` can only be applied to default traits like `Sized`
+//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
+//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
+
+struct S;
+impl !Trait2 for S {}
+impl Trait1 for S {}
+impl Trait3 for S {}
+
+fn main() {
+    foo(Box::new(S));
+    bar(&S);
+}
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr
new file mode 100644
index 00000000000..09c9fc31165
--- /dev/null
+++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr
@@ -0,0 +1,20 @@
+error: bound modifier `?` can only be applied to default traits like `Sized`
+  --> $DIR/more_maybe_bounds.rs:16:20
+   |
+LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+   |                    ^^^^^^^
+
+error: bound modifier `?` can only be applied to default traits like `Sized`
+  --> $DIR/more_maybe_bounds.rs:16:30
+   |
+LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+   |                              ^^^^^^^
+
+error: bound modifier `?` can only be applied to default traits like `Sized`
+  --> $DIR/more_maybe_bounds.rs:16:40
+   |
+LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
+   |                                        ^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
index 5f47778a140..8d1d3a4c790 100644
--- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
+++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.rs
@@ -2,9 +2,12 @@
 
 const fn maybe_const_maybe<T: [const] ?Sized>() {}
 //~^ ERROR `[const]` trait not allowed with `?` trait polarity modifier
+//~| ERROR `[const]` can only be applied to `const` traits
+//~| ERROR `[const]` can only be applied to `const` traits
 
 fn const_maybe<T: const ?Sized>() {}
 //~^ ERROR `const` trait not allowed with `?` trait polarity modifier
+//~| ERROR `const` can only be applied to `const` traits
 
 const fn maybe_const_negative<T: [const] !Trait>() {}
 //~^ ERROR `[const]` trait not allowed with `!` trait polarity modifier
diff --git a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
index 429131f905f..0ac40c51270 100644
--- a/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
+++ b/tests/ui/traits/const-traits/mutually-exclusive-trait-bound-modifiers.stderr
@@ -7,7 +7,7 @@ LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
    |                               there is not a well-defined meaning for a `[const] ?` trait
 
 error: `const` trait not allowed with `?` trait polarity modifier
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:8:25
    |
 LL | fn const_maybe<T: const ?Sized>() {}
    |                   ----- ^
@@ -15,7 +15,7 @@ LL | fn const_maybe<T: const ?Sized>() {}
    |                   there is not a well-defined meaning for a `const ?` trait
 
 error: `[const]` trait not allowed with `!` trait polarity modifier
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:12:42
    |
 LL | const fn maybe_const_negative<T: [const] !Trait>() {}
    |                                  ------- ^
@@ -23,7 +23,7 @@ LL | const fn maybe_const_negative<T: [const] !Trait>() {}
    |                                  there is not a well-defined meaning for a `[const] !` trait
 
 error: `const` trait not allowed with `!` trait polarity modifier
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:16:28
    |
 LL | fn const_negative<T: const !Trait>() {}
    |                      ----- ^
@@ -31,16 +31,44 @@ LL | fn const_negative<T: const !Trait>() {}
    |                      there is not a well-defined meaning for a `const !` trait
 
 error: negative bounds are not supported
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:42
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:12:42
    |
 LL | const fn maybe_const_negative<T: [const] !Trait>() {}
    |                                          ^
 
 error: negative bounds are not supported
-  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:16:28
    |
 LL | fn const_negative<T: const !Trait>() {}
    |                            ^
 
-error: aborting due to 6 previous errors
+error: `[const]` can only be applied to `const` traits
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31
+   |
+LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
+   |                               ^^^^^^^ can't be applied to `Sized`
+   |
+note: `Sized` can't be used with `[const]` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: `[const]` can only be applied to `const` traits
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31
+   |
+LL | const fn maybe_const_maybe<T: [const] ?Sized>() {}
+   |                               ^^^^^^^ can't be applied to `Sized`
+   |
+note: `Sized` can't be used with `[const]` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `const` can only be applied to `const` traits
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:8:19
+   |
+LL | fn const_maybe<T: const ?Sized>() {}
+   |                   ^^^^^ can't be applied to `Sized`
+   |
+note: `Sized` can't be used with `const` because it isn't `const`
+  --> $SRC_DIR/core/src/marker.rs:LL:COL
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
index 5069cd256b2..e7cca41a47e 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
@@ -64,4 +64,8 @@ fn main() {
     x.leak_foo();
     //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied
     x.maybe_leak_foo();
+    // Ensure that we validate the generic args of relaxed bounds in trait object types.
+    let _: dyn Trait + ?Leak<(), Undefined = ()>;
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR associated type `Undefined` not found for `Leak`
 }
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
index 48745e40268..350233b7cbe 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
@@ -18,6 +18,27 @@ note: required by a bound in `Trait::leak_foo`
 LL |     fn leak_foo(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
 
-error: aborting due to 2 previous errors
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:68:25
+   |
+LL |     let _: dyn Trait + ?Leak<(), Undefined = ()>;
+   |                         ^^^^-------------------- help: remove the unnecessary generics
+   |                         |
+   |                         expected 0 generic arguments
+   |
+note: trait defined here, with 0 generic parameters
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:44:12
+   |
+LL | auto trait Leak {}
+   |            ^^^^
+
+error[E0220]: associated type `Undefined` not found for `Leak`
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:68:34
+   |
+LL |     let _: dyn Trait + ?Leak<(), Undefined = ()>;
+   |                                  ^^^^^^^^^ associated type `Undefined` not found
+
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0107, E0220, E0277.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs
deleted file mode 100644
index 1ccd52bc169..00000000000
--- a/tests/ui/traits/maybe-polarity-pass.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#![feature(auto_traits)]
-#![feature(more_maybe_bounds)]
-#![feature(negative_impls)]
-
-trait Trait1 {}
-auto trait Trait2 {}
-
-trait Trait3 : ?Trait1 {}
-trait Trait4 where Self: Trait1 {}
-
-fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
-fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-
-struct S;
-impl !Trait2 for S {}
-impl Trait1 for S {}
-impl Trait3 for S {}
-
-fn main() {
-    foo(Box::new(S));
-    bar(&S);
-}
diff --git a/tests/ui/traits/maybe-polarity-pass.stderr b/tests/ui/traits/maybe-polarity-pass.stderr
deleted file mode 100644
index 1f378dd665a..00000000000
--- a/tests/ui/traits/maybe-polarity-pass.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-pass.rs:12:20
-   |
-LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-   |                    ^^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-pass.rs:12:30
-   |
-LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-   |                              ^^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-pass.rs:12:40
-   |
-LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
-   |                                        ^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs
deleted file mode 100644
index fd1ef567b3e..00000000000
--- a/tests/ui/traits/maybe-polarity-repeated.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(more_maybe_bounds)]
-
-trait Trait {}
-fn foo<T: ?Trait + ?Trait>(_: T) {}
-//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-
-fn main() {}
diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr
deleted file mode 100644
index 4fa1dc45bda..00000000000
--- a/tests/ui/traits/maybe-polarity-repeated.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/maybe-polarity-repeated.rs:4:11
-   |
-LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
-   |           ^^^^^^   ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-repeated.rs:4:11
-   |
-LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
-   |           ^^^^^^
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-polarity-repeated.rs:4:20
-   |
-LL | fn foo<T: ?Trait + ?Trait>(_: T) {}
-   |                    ^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0203`.
diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs
deleted file mode 100644
index 04963c98765..00000000000
--- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//! Test that ?Trait bounds are forbidden in supertraits and trait object types.
-//!
-//! While `?Sized` and other maybe bounds are allowed in type parameter bounds and where clauses,
-//! they are explicitly forbidden in certain syntactic positions:
-//! - As supertraits in trait definitions
-//! - In trait object type expressions
-//!
-//! See https://github.com/rust-lang/rust/issues/20503
-
-trait Tr: ?Sized {}
-//~^ ERROR `?Trait` is not permitted in supertraits
-
-type A1 = dyn Tr + (?Sized);
-//~^ ERROR `?Trait` is not permitted in trait object types
-type A2 = dyn for<'a> Tr + (?Sized);
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-fn main() {}
diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr
deleted file mode 100644
index bd0baa580bd..00000000000
--- a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0658]: `?Trait` is not permitted in supertraits
-  --> $DIR/maybe-trait-bounds-forbidden-locations.rs:10:11
-   |
-LL | trait Tr: ?Sized {}
-   |           ^^^^^^
-   |
-   = note: traits are `?Sized` by default
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-trait-bounds-forbidden-locations.rs:13:20
-   |
-LL | type A1 = dyn Tr + (?Sized);
-   |                    ^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-trait-bounds-forbidden-locations.rs:15:28
-   |
-LL | type A2 = dyn for<'a> Tr + (?Sized);
-   |                            ^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/wf-object/maybe-bound.rs b/tests/ui/traits/wf-object/maybe-bound.rs
deleted file mode 100644
index 17771e976ef..00000000000
--- a/tests/ui/traits/wf-object/maybe-bound.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects).
-
-trait Foo {}
-
-type _0 = dyn ?Sized + Foo;
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-type _1 = dyn Foo + ?Sized;
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-type _2 = dyn Foo + ?Sized + ?Sized;
-//~^ ERROR `?Trait` is not permitted in trait object types
-//~| ERROR `?Trait` is not permitted in trait object types
-
-type _3 = dyn ?Sized + Foo;
-//~^ ERROR `?Trait` is not permitted in trait object types
-
-fn main() {}
diff --git a/tests/ui/traits/wf-object/maybe-bound.stderr b/tests/ui/traits/wf-object/maybe-bound.stderr
deleted file mode 100644
index be7afabd0d0..00000000000
--- a/tests/ui/traits/wf-object/maybe-bound.stderr
+++ /dev/null
@@ -1,48 +0,0 @@
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:5:15
-   |
-LL | type _0 = dyn ?Sized + Foo;
-   |               ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:8:21
-   |
-LL | type _1 = dyn Foo + ?Sized;
-   |                     ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:11:21
-   |
-LL | type _2 = dyn Foo + ?Sized + ?Sized;
-   |                     ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:11:30
-   |
-LL | type _2 = dyn Foo + ?Sized + ?Sized;
-   |                              ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bound.rs:15:15
-   |
-LL | type _3 = dyn ?Sized + Foo;
-   |               ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/wf-object/only-maybe-bound.rs b/tests/ui/traits/wf-object/only-maybe-bound.rs
index 3e6db3e997c..96360e0331c 100644
--- a/tests/ui/traits/wf-object/only-maybe-bound.rs
+++ b/tests/ui/traits/wf-object/only-maybe-bound.rs
@@ -2,6 +2,6 @@
 
 type _0 = dyn ?Sized;
 //~^ ERROR at least one trait is required for an object type [E0224]
-//~| ERROR ?Trait` is not permitted in trait object types
+//~| ERROR relaxed bounds are not permitted in trait object types
 
 fn main() {}
diff --git a/tests/ui/traits/wf-object/only-maybe-bound.stderr b/tests/ui/traits/wf-object/only-maybe-bound.stderr
index 26269476eaa..6ae4568c699 100644
--- a/tests/ui/traits/wf-object/only-maybe-bound.stderr
+++ b/tests/ui/traits/wf-object/only-maybe-bound.stderr
@@ -1,11 +1,8 @@
-error[E0658]: `?Trait` is not permitted in trait object types
+error: relaxed bounds are not permitted in trait object types
   --> $DIR/only-maybe-bound.rs:3:15
    |
 LL | type _0 = dyn ?Sized;
    |               ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/only-maybe-bound.rs:3:11
@@ -15,5 +12,4 @@ LL | type _0 = dyn ?Sized;
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0224, E0658.
-For more information about an error, try `rustc --explain E0224`.
+For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs
index a4e49692c98..432aacb9be3 100644
--- a/tests/ui/type/pattern_types/validity.rs
+++ b/tests/ui/type/pattern_types/validity.rs
@@ -11,7 +11,7 @@ const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
 //~^ ERROR: constructing invalid value: encountered 0
 
 const BAD_UNINIT: pattern_type!(u32 is 1..) =
-    //~^ ERROR: using uninitialized data, but this operation requires initialized memory
+    //~^ ERROR: this operation requires initialized memory
     unsafe { std::mem::transmute(std::mem::MaybeUninit::<u32>::uninit()) };
 
 const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) };
@@ -27,7 +27,7 @@ const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) }));
 //~^ ERROR: constructing invalid value at .0.0: encountered 0
 
 const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') =
-    //~^ ERROR: using uninitialized data, but this operation requires initialized memory
+    //~^ ERROR: this operation requires initialized memory
     unsafe { std::mem::transmute(std::mem::MaybeUninit::<u32>::uninit()) };
 
 const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') };
diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr
index 4f4c16028f6..b545cd75ddb 100644
--- a/tests/ui/type/pattern_types/validity.stderr
+++ b/tests/ui/type/pattern_types/validity.stderr
@@ -9,11 +9,15 @@ LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
                HEX_DUMP
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> $DIR/validity.rs:13:1
    |
 LL | const BAD_UNINIT: pattern_type!(u32 is 1..) =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               __ __ __ __                                     │ ░░░░
+           }
 
 error[E0080]: unable to turn pointer into integer
   --> $DIR/validity.rs:17:1
@@ -46,11 +50,15 @@ LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) }));
                HEX_DUMP
            }
 
-error[E0080]: using uninitialized data, but this operation requires initialized memory
+error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
   --> $DIR/validity.rs:29:1
    |
 LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') =
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `CHAR_UNINIT` failed here
+   |
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               __ __ __ __                                     │ ░░░░
+           }
 
 error[E0080]: constructing invalid value: encountered 97, but expected something in the range 65..=89
   --> $DIR/validity.rs:33:1
diff --git a/tests/ui/typeck/issue-91334.stderr b/tests/ui/typeck/issue-91334.stderr
index 01e34919ce6..a348e1ebf7e 100644
--- a/tests/ui/typeck/issue-91334.stderr
+++ b/tests/ui/typeck/issue-91334.stderr
@@ -11,9 +11,8 @@ error: this file contains an unclosed delimiter
   --> $DIR/issue-91334.rs:7:23
    |
 LL | fn f(){||yield(((){),
-   |       -       -    - ^
-   |       |       |    |
-   |       |       |    missing open `(` for this delimiter
+   |       -       -      ^
+   |       |       |
    |       |       unclosed delimiter
    |       unclosed delimiter
 
diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/maybe-bounds-where.rs
deleted file mode 100644
index 4c4141631a7..00000000000
--- a/tests/ui/unsized/maybe-bounds-where.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-struct S1<T>(T) where (T): ?Sized;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-struct S2<T>(T) where u8: ?Sized;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-struct S3<T>(T) where &'static T: ?Sized;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-trait Trait<'a> {}
-
-struct S4<T>(T) where for<'a> T: ?Trait<'a>;
-//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-//~| ERROR relaxing a default bound only does something for `?Sized`
-
-struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
-//~^ ERROR type parameter has more than one relaxed default bound
-//~| ERROR relaxing a default bound only does something for `?Sized`
-
-impl<T> S1<T> {
-    fn f() where T: ?Sized {}
-    //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
-}
-
-fn main() {
-    let u = vec![1, 2, 3];
-    let _s: S5<[u8]> = S5(&u[..]); // OK
-}
diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/maybe-bounds-where.stderr
deleted file mode 100644
index fb6d37c2966..00000000000
--- a/tests/ui/unsized/maybe-bounds-where.stderr
+++ /dev/null
@@ -1,70 +0,0 @@
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:1:28
-   |
-LL | struct S1<T>(T) where (T): ?Sized;
-   |                            ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:4:27
-   |
-LL | struct S2<T>(T) where u8: ?Sized;
-   |                           ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:7:35
-   |
-LL | struct S3<T>(T) where &'static T: ?Sized;
-   |                                   ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:12:34
-   |
-LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
-   |                                  ^^^^^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared
-  --> $DIR/maybe-bounds-where.rs:21:21
-   |
-LL |     fn f() where T: ?Sized {}
-   |                     ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-bounds-where.rs:12:34
-   |
-LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
-   |                                  ^^^^^^^^^^
-
-error[E0203]: type parameter has more than one relaxed default bound, only one is supported
-  --> $DIR/maybe-bounds-where.rs:16:33
-   |
-LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
-   |                                 ^^^^^^^^^^^^^^^   ^^^^^^
-   |
-   = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
-  --> $DIR/maybe-bounds-where.rs:16:33
-   |
-LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
-   |                                 ^^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
-Some errors have detailed explanations: E0203, E0658.
-For more information about an error, try `rustc --explain E0203`.
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
new file mode 100644
index 00000000000..b8eda1e7786
--- /dev/null
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
@@ -0,0 +1,34 @@
+// Test various places where relaxed bounds are not permitted.
+//
+// Relaxed bounds are only permitted inside impl-Trait, assoc ty item bounds and
+// on type params defined by the closest item.
+
+struct S1<T>(T) where (T): ?Sized; //~ ERROR this relaxed bound is not permitted here
+
+struct S2<T>(T) where u8: ?Sized; //~ ERROR this relaxed bound is not permitted here
+
+struct S3<T>(T) where &'static T: ?Sized; //~ ERROR this relaxed bound is not permitted here
+
+trait Trait<'a> {}
+
+struct S4<T>(T) where for<'a> T: ?Trait<'a>;
+//~^ ERROR this relaxed bound is not permitted here
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+
+struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
+//~^ ERROR bound modifier `?` can only be applied to `Sized`
+
+impl<T> S1<T> {
+    fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here
+}
+
+trait Tr: ?Sized {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
+
+// Test that relaxed `Sized` bounds are rejected in trait object types:
+
+type O1 = dyn Tr + ?Sized; //~ ERROR relaxed bounds are not permitted in trait object types
+type O2 = dyn ?Sized + ?Sized + Tr;
+//~^ ERROR relaxed bounds are not permitted in trait object types
+//~| ERROR relaxed bounds are not permitted in trait object types
+
+fn main() {}
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
new file mode 100644
index 00000000000..30285d62693
--- /dev/null
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
@@ -0,0 +1,80 @@
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:6:28
+   |
+LL | struct S1<T>(T) where (T): ?Sized;
+   |                            ^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:8:27
+   |
+LL | struct S2<T>(T) where u8: ?Sized;
+   |                           ^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:10:35
+   |
+LL | struct S3<T>(T) where &'static T: ?Sized;
+   |                                   ^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:14:34
+   |
+LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
+   |                                  ^^^^^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:22:21
+   |
+LL |     fn f() where T: ?Sized {}
+   |                     ^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
+error: relaxed bounds are not permitted in supertrait bounds
+  --> $DIR/relaxed-bounds-invalid-places.rs:25:11
+   |
+LL | trait Tr: ?Sized {}
+   |           ^^^^^^
+   |
+   = note: traits are `?Sized` by default
+
+error: relaxed bounds are not permitted in trait object types
+  --> $DIR/relaxed-bounds-invalid-places.rs:29:20
+   |
+LL | type O1 = dyn Tr + ?Sized;
+   |                    ^^^^^^
+
+error: relaxed bounds are not permitted in trait object types
+  --> $DIR/relaxed-bounds-invalid-places.rs:30:15
+   |
+LL | type O2 = dyn ?Sized + ?Sized + Tr;
+   |               ^^^^^^
+
+error: relaxed bounds are not permitted in trait object types
+  --> $DIR/relaxed-bounds-invalid-places.rs:30:24
+   |
+LL | type O2 = dyn ?Sized + ?Sized + Tr;
+   |                        ^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/relaxed-bounds-invalid-places.rs:14:34
+   |
+LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
+   |                                  ^^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/relaxed-bounds-invalid-places.rs:18:33
+   |
+LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
+   |                                 ^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+