about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTshepang Mbambo <hopsi@tuta.io>2025-07-21 11:16:20 +0200
committerGitHub <noreply@github.com>2025-07-21 11:16:20 +0200
commit62e3a05291ef782cf212675d9e13c0b937c788c8 (patch)
tree57ddd8cbcb5f32bd2773165cc53b9c69d65ed720
parent4a45ab5ad4d6955285f79f331e677ecb5cdb60f1 (diff)
parentad20b064c30bbe9626e8c99f2b455cc6fd836d18 (diff)
downloadrust-62e3a05291ef782cf212675d9e13c0b937c788c8.tar.gz
rust-62e3a05291ef782cf212675d9e13c0b937c788c8.zip
Merge pull request #2512 from rust-lang/rustc-pull
Rustc pull update
-rw-r--r--.github/workflows/ci.yml5
-rw-r--r--Cargo.lock114
-rw-r--r--compiler/rustc_abi/src/lib.rs35
-rw-r--r--compiler/rustc_ast/Cargo.toml2
-rw-r--r--compiler/rustc_ast/src/ast.rs56
-rw-r--r--compiler/rustc_ast/src/util/literal.rs6
-rw-r--r--compiler/rustc_ast/src/visit.rs3
-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.rs125
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs142
-rw-r--r--compiler/rustc_ast_passes/messages.ftl9
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs61
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs18
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs2
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs22
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs10
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs4
-rw-r--r--compiler/rustc_attr_data_structures/src/stability.rs4
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs20
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg.rs53
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs41
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs18
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs58
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs57
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs33
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs47
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/mod.rs2
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/m68k.yml40
-rw-r--r--compiler/rustc_codegen_gcc/.github/workflows/release.yml3
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock502
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml39
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/lib.rs1
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/build.rs38
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/config.rs5
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/utils.rs13
-rw-r--r--compiler/rustc_codegen_gcc/doc/tips.md6
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs17
-rw-r--r--compiler/rustc_codegen_gcc/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/back/lto.rs15
-rw-r--r--compiler/rustc_codegen_gcc/src/back/write.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs40
-rw-r--r--compiler/rustc_codegen_gcc/src/mono_item.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt2
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs1
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/float.rs16
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/int.rs2
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/volatile.rs3
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/volatile2.rs6
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl1
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs49
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs33
-rw-r--r--compiler/rustc_codegen_ssa/src/back/lto.rs60
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs174
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs125
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs24
-rw-r--r--compiler/rustc_const_eval/messages.ftl11
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/dummy_machine.rs1
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs55
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs17
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs29
-rw-r--r--compiler/rustc_const_eval/src/errors.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs92
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs99
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs64
-rw-r--r--compiler/rustc_const_eval/src/interpret/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs12
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs13
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs46
-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_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/build.rs10
-rw-r--r--compiler/rustc_expand/src/config.rs22
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs5
-rw-r--r--compiler/rustc_hir/src/definitions.rs36
-rw-r--r--compiler/rustc_hir/src/hir.rs23
-rw-r--r--compiler/rustc_hir/src/intravisit.rs10
-rw-r--r--compiler/rustc_hir/src/target.rs29
-rw-r--r--compiler/rustc_hir/src/tests.rs3
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl19
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs71
-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.rs70
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs3
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs11
-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_hir_typeck/src/fn_ctxt/_impl.rs51
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs28
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs15
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs11
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs21
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs20
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/undo_log.rs4
-rw-r--r--compiler/rustc_interface/src/passes.rs6
-rw-r--r--compiler/rustc_lint/messages.ftl63
-rw-r--r--compiler/rustc_lint/src/builtin.rs5
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs3
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lifetime_syntax.rs149
-rw-r--r--compiler/rustc_lint/src/lints.rs94
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs2
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs4
-rw-r--r--compiler/rustc_lint/src/types/literal.rs42
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs5
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp18
-rw-r--r--compiler/rustc_metadata/src/creader.rs286
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_middle/src/hir/map.rs2
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs14
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs22
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs45
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs7
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs13
-rw-r--r--compiler/rustc_middle/src/query/mod.rs30
-rw-r--r--compiler/rustc_middle/src/ty/context.rs48
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs29
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs32
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs553
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs44
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs18
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs12
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs14
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs6
-rw-r--r--compiler/rustc_parse/Cargo.toml2
-rw-r--r--compiler/rustc_parse/messages.ftl1
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-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_parse/src/parser/item.rs28
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
-rw-r--r--compiler/rustc_parse_format/Cargo.toml2
-rw-r--r--compiler/rustc_passes/messages.ftl9
-rw-r--r--compiler/rustc_passes/src/check_attr.rs144
-rw-r--r--compiler/rustc_passes/src/errors.rs13
-rw-r--r--compiler/rustc_passes/src/lang_items.rs2
-rw-r--r--compiler/rustc_passes/src/lib_features.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs972
-rw-r--r--compiler/rustc_privacy/src/lib.rs9
-rw-r--r--compiler/rustc_proc_macro/Cargo.toml2
-rw-r--r--compiler/rustc_public/src/rustc_internal/mod.rs18
-rw-r--r--compiler/rustc_public/src/unstable/convert/stable/ty.rs3
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs80
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs78
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs9
-rw-r--r--compiler/rustc_resolve/src/ident.rs6
-rw-r--r--compiler/rustc_resolve/src/imports.rs32
-rw-r--r--compiler/rustc_resolve/src/late.rs16
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs47
-rw-r--r--compiler/rustc_resolve/src/lib.rs113
-rw-r--r--compiler/rustc_resolve/src/macros.rs4
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs10
-rw-r--r--compiler/rustc_session/src/config.rs5
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs40
-rw-r--r--compiler/rustc_span/src/def_id.rs18
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs25
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs30
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs2
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs4
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs34
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs100
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_traits/src/coroutine_witnesses.rs58
-rw-r--r--compiler/rustc_traits/src/evaluate_obligation.rs2
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs1
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs11
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs54
-rw-r--r--compiler/rustc_type_ir/src/flags.rs19
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs37
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs2
-rw-r--r--compiler/rustc_type_ir/src/interner.rs8
-rw-r--r--compiler/rustc_type_ir/src/predicate_kind.rs10
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs1
-rw-r--r--compiler/rustc_type_ir/src/visit.rs4
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/alloc/src/boxed/thin.rs7
-rw-r--r--library/alloc/src/fmt.rs4
-rw-r--r--library/core/src/any.rs2
-rw-r--r--library/core/src/async_iter/async_iter.rs10
-rw-r--r--library/core/src/cmp.rs8
-rw-r--r--library/core/src/cmp/bytewise.rs8
-rw-r--r--library/core/src/ffi/c_str.rs26
-rw-r--r--library/core/src/fmt/mod.rs1
-rw-r--r--library/core/src/fmt/num.rs8
-rw-r--r--library/core/src/intrinsics/mod.rs30
-rw-r--r--library/core/src/io/borrowed_buf.rs35
-rw-r--r--library/core/src/iter/adapters/zip.rs74
-rw-r--r--library/core/src/iter/traits/collect.rs1
-rw-r--r--library/core/src/iter/traits/iterator.rs8
-rw-r--r--library/core/src/lib.rs9
-rw-r--r--library/core/src/macros/mod.rs2
-rw-r--r--library/core/src/mem/maybe_uninit.rs114
-rw-r--r--library/core/src/mem/mod.rs2
-rw-r--r--library/core/src/net/ip_addr.rs1
-rw-r--r--library/core/src/num/f128.rs6
-rw-r--r--library/core/src/num/f16.rs6
-rw-r--r--library/core/src/num/f32.rs6
-rw-r--r--library/core/src/num/f64.rs6
-rw-r--r--library/core/src/num/int_log10.rs4
-rw-r--r--library/core/src/num/nonzero.rs5
-rw-r--r--library/core/src/num/uint_macros.rs45
-rw-r--r--library/core/src/option.rs140
-rw-r--r--library/core/src/prelude/v1.rs2
-rw-r--r--library/core/src/primitive_docs.rs1
-rw-r--r--library/core/src/ptr/docs/as_uninit_slice.md20
-rw-r--r--library/core/src/ptr/mod.rs168
-rw-r--r--library/core/src/slice/cmp.rs22
-rw-r--r--library/core/src/slice/mod.rs3
-rw-r--r--library/core/src/str/mod.rs1
-rw-r--r--library/core/src/str/traits.rs3
-rw-r--r--library/core/src/ub_checks.rs18
-rw-r--r--library/coretests/tests/io/borrowed_buf.rs8
-rw-r--r--library/coretests/tests/iter/adapters/cloned.rs3
-rw-r--r--library/coretests/tests/iter/adapters/zip.rs119
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/proc_macro/Cargo.toml2
-rw-r--r--library/proc_macro/src/lib.rs6
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/io/mod.rs6
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/num/f32.rs12
-rw-r--r--library/std/src/num/f64.rs12
-rw-r--r--library/std/src/prelude/v1.rs2
-rw-r--r--library/std/src/sync/poison.rs2
-rw-r--r--library/std/src/sys/pal/windows/c.rs69
-rw-r--r--library/windows_targets/src/lib.rs23
-rw-r--r--src/bootstrap/README.md2
-rw-r--r--src/bootstrap/bootstrap.py7
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs90
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs25
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs30
-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.rs45
-rw-r--r--src/bootstrap/src/core/config/config.rs8
-rw-r--r--src/bootstrap/src/core/config/toml/llvm.rs16
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs28
-rw-r--r--src/bootstrap/src/lib.rs68
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/build_helper/src/lib.rs1
-rw-r--r--src/build_helper/src/npm.rs30
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile8
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile14
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile14
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile8
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile11
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version1
-rwxr-xr-xsrc/ci/docker/run.sh12
-rwxr-xr-xsrc/ci/docker/scripts/i686-gnu-nopt-2.sh6
-rwxr-xr-xsrc/ci/docker/scripts/x86_64-gnu-llvm2.sh2
-rw-r--r--src/ci/github-actions/jobs.yml16
-rwxr-xr-xsrc/ci/scripts/install-mingw.sh5
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/effects.md9
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md8
-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/mod.rs5
-rw-r--r--src/librustdoc/clean/types.rs6
-rw-r--r--src/librustdoc/clean/utils.rs17
-rw-r--r--src/librustdoc/doctest.rs4
-rw-r--r--src/librustdoc/doctest/rust.rs2
-rw-r--r--src/librustdoc/formats/cache.rs4
-rw-r--r--src/librustdoc/formats/renderer.rs4
-rw-r--r--src/librustdoc/html/format.rs35
-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.rs88
-rw-r--r--src/librustdoc/html/render/mod.rs50
-rw-r--r--src/librustdoc/html/render/ordered_json.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs89
-rw-r--r--src/librustdoc/html/render/search_index.rs16
-rw-r--r--src/librustdoc/html/render/sidebar.rs2
-rw-r--r--src/librustdoc/html/render/sorted_template.rs3
-rw-r--r--src/librustdoc/html/render/write_shared.rs4
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts7
-rw-r--r--src/librustdoc/html/static/js/search.js150
-rw-r--r--src/librustdoc/html/url_parts_builder.rs12
-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
m---------src/llvm-project0
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs17
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.fixed3
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.rs3
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed3
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs3
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr11
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed3
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs3
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr6
-rw-r--r--src/tools/compiletest/src/common.rs62
-rw-r--r--src/tools/compiletest/src/directives.rs59
-rw-r--r--src/tools/compiletest/src/lib.rs19
-rw-r--r--src/tools/compiletest/src/runtest.rs7
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs53
-rw-r--r--src/tools/lint-docs/Cargo.toml2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs2
-rw-r--r--src/tools/miri/src/bin/log/tracing_chrome.rs72
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/machine.rs4
-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/panic/mir-validation.stderr14
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-time.rs6
-rw-r--r--src/tools/miri/tests/pass/intrinsics/type-id.rs19
-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/rust-analyzer/Cargo.lock82
-rw-r--r--src/tools/rust-analyzer/Cargo.toml20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs405
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs139
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/signatures.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs142
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs409
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs1000
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs69
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs87
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs53
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt68
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs6
-rwxr-xr-xsrc/tools/rust-analyzer/crates/ide/src/folding_ranges.rs52
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs65
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs36
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs27
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/parser.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rast10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rs1
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs34
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs395
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/env.rs137
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs23
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs9
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_tuple.rs50
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/version.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs126
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs3
-rw-r--r--src/tools/rust-analyzer/crates/span/src/ast_id.rs42
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs36
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs19
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs13
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs4
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs132
-rwxr-xr-xsrc/tools/rust-analyzer/lib/lsp-server/examples/manual_test.sh53
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/examples/minimal_lsp.rs335
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs2
-rw-r--r--src/tools/rustbook/Cargo.lock55
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs93
-rw-r--r--src/tools/rustdoc-js/tester.js71
-rw-r--r--src/tools/rustfmt/src/items.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/issues.txt2
-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--src/tools/unicode-table-generator/Cargo.toml2
-rw-r--r--src/tools/unicode-table-generator/src/cascading_map.rs14
-rw-r--r--src/tools/unicode-table-generator/src/case_mapping.rs2
-rw-r--r--src/tools/unicode-table-generator/src/main.rs40
-rw-r--r--src/tools/unicode-table-generator/src/raw_emitter.rs25
-rw-r--r--tests/assembly/cstring-merging.rs2
-rw-r--r--tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs14
-rw-r--r--tests/assembly/wasm_exceptions.rs1
-rw-r--r--tests/codegen/enum/enum-discriminant-eq.rs223
-rw-r--r--tests/codegen/enum/enum-match.rs326
-rw-r--r--tests/codegen/fn-parameters-on-different-lines-debuginfo.rs22
-rw-r--r--tests/codegen/repeat-operand-zero-len.rs28
-rw-r--r--tests/codegen/repeat-operand-zst-elem.rs28
-rw-r--r--tests/codegen/sanitizer/kcfi/naked-function.rs47
-rw-r--r--tests/crashes/117629.rs3
-rw-r--r--tests/crashes/133275-1.rs13
-rw-r--r--tests/crashes/133275-2.rs15
-rw-r--r--tests/crashes/const_mut_ref_check_bypass.rs11
-rw-r--r--tests/mir-opt/const_prop/transmute.rs2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff2
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff2
-rw-r--r--tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff3
-rw-r--r--tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff3
-rw-r--r--tests/mir-opt/gvn.rs2
-rw-r--r--tests/mir-opt/inline/cycle.rs2
-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/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir5
-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/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr10
-rw-r--r--tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr10
-rw-r--r--tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr10
-rw-r--r--tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr10
-rw-r--r--tests/run-make/const-trait-stable-toolchain/rmake.rs10
-rw-r--r--tests/run-make/export-executable-symbols/rmake.rs26
-rw-r--r--tests/run-make/link-eh-frame-terminator/rmake.rs1
-rw-r--r--tests/run-make/mte-ffi/bar.h2
-rw-r--r--tests/run-make/mte-ffi/bar_float.c4
-rw-r--r--tests/run-make/mte-ffi/bar_int.c2
-rw-r--r--tests/run-make/mte-ffi/bar_string.c3
-rw-r--r--tests/run-make/mte-ffi/rmake.rs7
-rw-r--r--tests/run-make/option-output-no-space/main.rs1
-rw-r--r--tests/run-make/option-output-no-space/rmake.rs95
-rw-r--r--tests/rustdoc-js-std/alias-lev.js11
-rw-r--r--tests/rustdoc-js/non-english-identifier.js17
-rw-r--r--tests/rustdoc-ui/check-doc-alias-attr-location.stderr4
-rw-r--r--tests/rustdoc/reexport/auxiliary/reexports-attrs.rs14
-rw-r--r--tests/rustdoc/reexport/reexport-attrs.rs20
-rw-r--r--tests/ui/asm/naked-function-shim.rs31
-rw-r--r--tests/ui/asm/naked-invalid-attr.stderr2
-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/async-await/async-closures/def-path.stderr4
-rw-r--r--tests/ui/async-await/async-drop/foreign-fundamental.rs21
-rw-r--r--tests/ui/async-await/async-drop/foreign-fundamental.stderr24
-rw-r--r--tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr (renamed from tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr)8
-rw-r--r--tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs6
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr38
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-1.rs48
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr21
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr21
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-10.rs35
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr20
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr20
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-11.rs31
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr18
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-12.rs40
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr41
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr60
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-13.rs68
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr33
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-14.rs29
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr21
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-15.rs21
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr25
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr25
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-16.rs23
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr29
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-17.rs30
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr49
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-2.rs23
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr12
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-3.rs72
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr10
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-4.rs34
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr13
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-5.rs54
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr50
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-6.rs59
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr8
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-7.rs33
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr10
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-8.rs27
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr11
-rw-r--r--tests/ui/async-await/higher-ranked-auto-trait-9.rs44
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr (renamed from tests/ui/async-await/return-type-notation/issue-110963-early.stderr)4
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.rs5
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr26
-rw-r--r--tests/ui/attributes/positions/used.stderr2
-rw-r--r--tests/ui/cast/cast-char.rs56
-rw-r--r--tests/ui/cast/cast-char.stderr124
-rw-r--r--tests/ui/cfg/crt-static-with-target-features-works.rs24
-rw-r--r--tests/ui/cfg/crt-static-with-target-features-works.stderr8
-rw-r--r--tests/ui/check-cfg/cfg-crate-features.rs13
-rw-r--r--tests/ui/check-cfg/cfg-crate-features.stderr33
-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/const-generics/type-dependent/issue-71348.full.stderr11
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.rs2
-rw-r--r--tests/ui/consts/const-compare-bytes-ub.rs2
-rw-r--r--tests/ui/consts/const-compare-bytes-ub.stderr8
-rw-r--r--tests/ui/consts/const-compare-bytes.rs2
-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/auxiliary/stability.rs9
-rw-r--r--tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr12
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs4
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr2
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs6
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs11
-rw-r--r--tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr8
-rw-r--r--tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs2
-rw-r--r--tests/ui/consts/const-eval/heap/make-global-dangling.rs18
-rw-r--r--tests/ui/consts/const-eval/heap/make-global-dangling.stderr15
-rw-r--r--tests/ui/consts/const-eval/heap/make-global-other.rs15
-rw-r--r--tests/ui/consts/const-eval/heap/make-global-other.stderr9
-rw-r--r--tests/ui/consts/const-eval/heap/make-global-twice.rs18
-rw-r--r--tests/ui/consts/const-eval/heap/make-global-twice.stderr9
-rw-r--r--tests/ui/consts/const-eval/heap/make-global.rs21
-rw-r--r--tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs15
-rw-r--r--tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr9
-rw-r--r--tests/ui/consts/const-eval/heap/ptr_not_made_global.rs24
-rw-r--r--tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr18
-rw-r--r--tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs11
-rw-r--r--tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr10
-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/consts/const-size_of_val-align_of_val-extern-type.rs4
-rw-r--r--tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr38
-rw-r--r--tests/ui/consts/const-try.rs4
-rw-r--r--tests/ui/consts/const-try.stderr8
-rw-r--r--tests/ui/consts/const_transmute_type_id4.rs2
-rw-r--r--tests/ui/consts/const_transmute_type_id4.stderr2
-rw-r--r--tests/ui/consts/const_transmute_type_id5.rs9
-rw-r--r--tests/ui/consts/const_transmute_type_id5.stderr6
-rw-r--r--tests/ui/consts/rustc-const-stability-require-const.stderr48
-rw-r--r--tests/ui/consts/rustc-impl-const-stability.stderr4
-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/coroutine/clone-impl.rs25
-rw-r--r--tests/ui/coroutine/clone-impl.stderr113
-rw-r--r--tests/ui/coroutine/print/coroutine-print-verbose-3.stderr2
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.feat.stderr7
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr27
-rw-r--r--tests/ui/coverage-attr/bad-syntax.stderr134
-rw-r--r--tests/ui/coverage-attr/name-value.rs7
-rw-r--r--tests/ui/coverage-attr/name-value.stderr179
-rw-r--r--tests/ui/coverage-attr/subword.stderr33
-rw-r--r--tests/ui/coverage-attr/word-only.rs7
-rw-r--r--tests/ui/coverage-attr/word-only.stderr185
-rw-r--r--tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr (renamed from tests/ui/deduplicate-diagnostics.deduplicate.stderr)4
-rw-r--r--tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr (renamed from tests/ui/deduplicate-diagnostics.duplicate.stderr)10
-rw-r--r--tests/ui/diagnostic-flags/deduplicate-diagnostics.rs (renamed from tests/ui/deduplicate-diagnostics.rs)2
-rw-r--r--tests/ui/error-codes/E0120.rs2
-rw-r--r--tests/ui/expr/weird-exprs.rs (renamed from tests/ui/expr/syntax-edge-cases-lint-clean.rs)0
-rw-r--r--tests/ui/extern/extern-types-field-offset.rs2
-rw-r--r--tests/ui/extern/extern-types-size_of_val.rs4
-rw-r--r--tests/ui/extern/extern-types-size_of_val.stderr39
-rw-r--r--tests/ui/extern/extern-types-unsized.rs2
-rw-r--r--tests/ui/extern/extern-types-unsized.stderr30
-rw-r--r--tests/ui/extern/unsized-extern-derefmove.rs4
-rw-r--r--tests/ui/extern/unsized-extern-derefmove.stderr52
-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/feature-gates/issue-43106-gating-of-builtin-attrs.rs6
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr274
-rw-r--r--tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr22
-rw-r--r--tests/ui/fmt/println-debug-different-types.rs (renamed from tests/ui/log-poly.rs)4
-rw-r--r--tests/ui/generic-associated-types/bugs/issue-100013.stderr48
-rw-r--r--tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr24
-rw-r--r--tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs (renamed from tests/ui/generic-associated-types/bugs/issue-100013.rs)18
-rw-r--r--tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr (renamed from tests/ui/generic-associated-types/issue-92096.stderr)2
-rw-r--r--tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs24
-rw-r--r--tests/ui/generic-associated-types/issue-92096.rs28
-rw-r--r--tests/ui/impl-trait/call_method_without_import.no_import.stderr7
-rw-r--r--tests/ui/impl-trait/in-bindings/implicit-sized.rs19
-rw-r--r--tests/ui/impl-trait/in-bindings/implicit-sized.stderr11
-rw-r--r--tests/ui/impl-trait/issues/issue-55872-3.rs1
-rw-r--r--tests/ui/impl-trait/issues/issue-55872-3.stderr16
-rw-r--r--tests/ui/impl-trait/no-method-suggested-traits.stderr8
-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/impl-trait/rpit-assoc-pair-with-lifetime.rs2
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr7
-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/layout/unconstrained-param-ice-137308.rs1
-rw-r--r--tests/ui/layout/unconstrained-param-ice-137308.stderr11
-rw-r--r--tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs18
-rw-r--r--tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr11
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs2
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr9
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs8
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr36
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs4
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr18
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs8
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr36
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs104
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr497
-rw-r--r--tests/ui/linking/export-executable-symbols.rs30
-rw-r--r--tests/ui/linking/ld64-cross-compilation.rs (renamed from tests/ui/darwin-ld64.rs)8
-rw-r--r--tests/ui/lint/invalid_null_args.rs5
-rw-r--r--tests/ui/lint/invalid_null_args.stderr58
-rw-r--r--tests/ui/lint/lint-double-negations-macro.rs16
-rw-r--r--tests/ui/lint/lint-double-negations-macro.stderr20
-rw-r--r--tests/ui/lint/lint-stability-deprecated.stderr20
-rw-r--r--tests/ui/lint/lint-stability.stderr18
-rw-r--r--tests/ui/lint/unused/unused-attr-duplicate.rs4
-rw-r--r--tests/ui/lint/unused/unused-attr-duplicate.stderr36
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.stderr4
-rw-r--r--tests/ui/lto/debuginfo-lto-alloc.rs3
-rw-r--r--tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr16
-rw-r--r--tests/ui/methods/wrong-ambig-message.rs34
-rw-r--r--tests/ui/methods/wrong-ambig-message.stderr30
-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/gvn-nonsensical-coroutine-layout.rs (renamed from tests/crashes/128094.rs)6
-rw-r--r--tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr26
-rw-r--r--tests/ui/mir/gvn-nonsensical-sized-str.rs (renamed from tests/crashes/135128.rs)5
-rw-r--r--tests/ui/mir/gvn-nonsensical-sized-str.stderr10
-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/mir/validate/critical-edge.rs4
-rw-r--r--tests/ui/missing/missing-stability.stderr9
-rw-r--r--tests/ui/nll/issue-50716.rs2
-rw-r--r--tests/ui/nll/issue-50716.stderr18
-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.rs35
-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.rs8
-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.rs8
-rw-r--r--tests/ui/privacy/effective_visibilities_invariants.stderr2
-rw-r--r--tests/ui/privacy/issue-113860-1.stderr18
-rw-r--r--tests/ui/privacy/issue-113860-2.stderr18
-rw-r--r--tests/ui/privacy/issue-113860.stderr18
-rw-r--r--tests/ui/privacy/private-in-public-warn.rs12
-rw-r--r--tests/ui/privacy/private-in-public-warn.stderr74
-rw-r--r--tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs1
-rw-r--r--tests/ui/privacy/pub-priv-dep/pub-priv1.rs20
-rw-r--r--tests/ui/privacy/pub-priv-dep/pub-priv1.stderr66
-rw-r--r--tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs13
-rw-r--r--tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr20
-rw-r--r--tests/ui/rustdoc/check-doc-alias-attr-location.stderr4
-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/self/elision/ignore-non-reference-lifetimes.rs4
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.stderr18
-rw-r--r--tests/ui/self/self_lifetime-async.rs4
-rw-r--r--tests/ui/self/self_lifetime-async.stderr18
-rw-r--r--tests/ui/self/self_lifetime.rs4
-rw-r--r--tests/ui/self/self_lifetime.stderr18
-rw-r--r--tests/ui/shadowed/shadowing-generic-item.rs (renamed from tests/ui/lexical-scopes.rs)2
-rw-r--r--tests/ui/shadowed/shadowing-generic-item.stderr (renamed from tests/ui/lexical-scopes.stderr)4
-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/incomplete-inference-issue-143992.current_sized_hierarchy.stderr17
-rw-r--r--tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr17
-rw-r--r--tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs33
-rw-r--r--tests/ui/sized-hierarchy/overflow.current.stderr45
-rw-r--r--tests/ui/sized-hierarchy/overflow.rs6
-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/specialization/const_trait_impl.stderr24
-rw-r--r--tests/ui/stability-attribute/missing-const-stability.rs3
-rw-r--r--tests/ui/stability-attribute/missing-const-stability.stderr18
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity-3.stderr6
-rw-r--r--tests/ui/std/issue-81357-unsound-file-methods.rs2
-rw-r--r--tests/ui/structs/default-field-values/const-trait-default-field-value.rs37
-rw-r--r--tests/ui/suggestions/issue-94171.stderr4
-rw-r--r--tests/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--tests/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--tests/ui/symbol-names/struct-constructor-mangling.rs (renamed from tests/ui/struct-ctor-mangling.rs)4
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout8
-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/conditionally-const-invalid-places.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs13
-rw-r--r--tests/ui/traits/const-traits/const-bounds-non-const-trait.rs6
-rw-r--r--tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr12
-rw-r--r--tests/ui/traits/const-traits/const-impl-requires-const-trait.rs2
-rw-r--r--tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr6
-rw-r--r--tests/ui/traits/const-traits/const-impl-trait.rs2
-rw-r--r--tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs8
-rw-r--r--tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr20
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-gate.rs2
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr5
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr4
-rw-r--r--tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs2
-rw-r--r--tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr4
-rw-r--r--tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs4
-rw-r--r--tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr8
-rw-r--r--tests/ui/traits/const-traits/imply-always-const.rs19
-rw-r--r--tests/ui/traits/const-traits/match-non-const-eq.gated.stderr12
-rw-r--r--tests/ui/traits/const-traits/match-non-const-eq.rs9
-rw-r--r--tests/ui/traits/const-traits/match-non-const-eq.stock.stderr22
-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/const-traits/spec-effectvar-ice.rs6
-rw-r--r--tests/ui/traits/const-traits/spec-effectvar-ice.stderr16
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr14
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr20
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-2.rs10
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr2
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr22
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr22
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.rs14
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr22
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr20
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr10
-rw-r--r--tests/ui/traits/const-traits/trait-default-body-stability.stderr8
-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/next-solver/cycles/normalizes-to-is-not-productive.stderr7
-rw-r--r--tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr19
-rw-r--r--tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr16
-rw-r--r--tests/ui/traits/resolve-impl-before-constrain-check.rs1
-rw-r--r--tests/ui/traits/resolve-impl-before-constrain-check.stderr11
-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/underscore-lifetime/raw-underscore-lifetime.rs9
-rw-r--r--tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr8
-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
-rw-r--r--tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs25
-rw-r--r--tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs19
-rw-r--r--tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs13
-rw-r--r--tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs11
-rw-r--r--tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs20
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs35
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr11
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs12
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr13
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr13
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs18
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs11
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr13
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs14
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr17
-rw-r--r--tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs42
-rw-r--r--tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr22
-rw-r--r--tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs28
-rw-r--r--tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr17
-rw-r--r--tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs30
-rw-r--r--tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs27
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr17
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs40
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs14
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr10
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs36
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr18
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs13
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr9
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_codegen.rs13
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr13
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr13
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_coherence.rs17
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs15
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr14
-rw-r--r--tests/ui/unstable-feature-bound/unstable_inherent_method.rs23
-rw-r--r--tests/ui/unstable-feature-bound/unstable_inherent_method.stderr20
-rw-r--r--tests/ui/where-clauses/ignore-err-clauses.rs2
-rw-r--r--tests/ui/where-clauses/ignore-err-clauses.stderr29
-rw-r--r--triagebot.toml8
1149 files changed, 17812 insertions, 8947 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dc8ac539a3a..e92afc14c20 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -182,11 +182,6 @@ jobs:
       - name: install MinGW
         run: src/ci/scripts/install-mingw.sh
 
-      # Workaround for spurious ci failures after mingw install
-      # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775
-      - name: ensure home dir exists
-        run: mkdir -p ~
-
       - name: install ninja
         run: src/ci/scripts/install-ninja.sh
 
diff --git a/Cargo.lock b/Cargo.lock
index b8a8d7b7d23..1f7470e96c5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -216,7 +216,7 @@ dependencies = [
  "memchr",
  "serde",
  "serde_derive",
- "winnow 0.7.11",
+ "winnow 0.7.12",
 ]
 
 [[package]]
@@ -470,23 +470,12 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz"
-version = "0.10.3"
+version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efdce149c370f133a071ca8ef6ea340b7b88748ab0810097a9e2976eaa34b4f3"
+checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3"
 dependencies = [
  "chrono",
- "chrono-tz-build",
- "phf",
-]
-
-[[package]]
-name = "chrono-tz-build"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f10f8c9340e31fc120ff885fcdb54a0b48e474bbd77cab557f0c30a3e569402"
-dependencies = [
- "parse-zoneinfo",
- "phf_codegen",
+ "phf 0.12.1",
 ]
 
 [[package]]
@@ -501,9 +490,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
+checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -521,9 +510,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
+checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
 dependencies = [
  "anstream",
  "anstyle",
@@ -533,9 +522,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
+checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
 dependencies = [
  "heck 0.5.0",
  "proc-macro2",
@@ -798,9 +787,9 @@ dependencies = [
 
 [[package]]
 name = "crc32fast"
-version = "1.4.2"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
 dependencies = [
  "cfg-if",
 ]
@@ -989,9 +978,9 @@ dependencies = [
 
 [[package]]
 name = "derive_setters"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9c848e86c87e5cc305313041c5677d4d95d60baa71cf95e5f6ea2554bb629ff"
+checksum = "ae5c625eda104c228c06ecaf988d1c60e542176bd7a490e60eeda3493244c0c9"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -2045,9 +2034,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
 
 [[package]]
 name = "libredox"
-version = "0.1.4"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
+checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
 dependencies = [
  "bitflags",
  "libc",
@@ -2157,7 +2146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
 dependencies = [
  "log",
- "phf",
+ "phf 0.11.3",
  "phf_codegen",
  "string_cache",
  "string_cache_codegen",
@@ -2196,9 +2185,9 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "12.0.1"
+version = "12.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "570a507d8948a66a97f42cbbaf8a6bb9516a51017d4ee949502ad7a10a864395"
+checksum = "6ebd1ebda747ae161a4a377bf93f87e18d46faad2331cc0c7d25b84b1d445f49"
 dependencies = [
  "log",
  "memmap2",
@@ -2633,15 +2622,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "parse-zoneinfo"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
-dependencies = [
- "regex",
-]
-
-[[package]]
 name = "pathdiff"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2712,7 +2692,16 @@ version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
 dependencies = [
- "phf_shared",
+ "phf_shared 0.11.3",
+]
+
+[[package]]
+name = "phf"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
+dependencies = [
+ "phf_shared 0.12.1",
 ]
 
 [[package]]
@@ -2722,7 +2711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
 dependencies = [
  "phf_generator",
- "phf_shared",
+ "phf_shared 0.11.3",
 ]
 
 [[package]]
@@ -2731,7 +2720,7 @@ version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
 dependencies = [
- "phf_shared",
+ "phf_shared 0.11.3",
  "rand 0.8.5",
 ]
 
@@ -2745,6 +2734,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "phf_shared"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
 name = "pin-project-lite"
 version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3136,9 +3134,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
 
 [[package]]
 name = "rustc-literal-escaper"
-version = "0.0.4"
+version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
+checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
 
 [[package]]
 name = "rustc-main"
@@ -4752,15 +4750,15 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "1.0.7"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -4860,9 +4858,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.140"
+version = "1.0.141"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
 dependencies = [
  "itoa",
  "memchr",
@@ -5027,7 +5025,7 @@ checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
 dependencies = [
  "new_debug_unreachable",
  "parking_lot",
- "phf_shared",
+ "phf_shared 0.11.3",
  "precomputed-hash",
  "serde",
 ]
@@ -5039,7 +5037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
 dependencies = [
  "phf_generator",
- "phf_shared",
+ "phf_shared 0.11.3",
  "proc-macro2",
  "quote",
 ]
@@ -5104,9 +5102,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.36.0"
+version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aab138f5c1bb35231de19049060a87977ad23e04f2303e953bc5c2947ac7dec4"
+checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
 dependencies = [
  "libc",
  "objc2-core-foundation",
@@ -5411,7 +5409,7 @@ dependencies = [
  "serde_spanned",
  "toml_datetime",
  "toml_write",
- "winnow 0.7.11",
+ "winnow 0.7.12",
 ]
 
 [[package]]
@@ -5829,9 +5827,9 @@ dependencies = [
 
 [[package]]
 name = "wasi-preview1-component-adapter-provider"
-version = "34.0.1"
+version = "34.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafa1e6af9a954a4bcf6ef420c33355d0ce84ddc6afbcba7bb6f05126f9120ae"
+checksum = "33696c5f1ff1e083de9f36c3da471abd736362bc173e093f8b0b1ed5a387e39b"
 
 [[package]]
 name = "wasm-bindgen"
@@ -6475,9 +6473,9 @@ dependencies = [
 
 [[package]]
 name = "winnow"
-version = "0.7.11"
+version = "0.7.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
+checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
 dependencies = [
  "memchr",
 ]
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/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 5de2e69072f..155e14a3796 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2024"
 # tidy-alphabetical-start
 bitflags = "2.4.1"
 memchr = "2.7.4"
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 rustc_ast_ir = { path = "../rustc_ast_ir" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3c576316f62..8c2b521c560 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -18,7 +18,7 @@
 //! - [`Attribute`]: Metadata associated with item.
 //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
 
-use std::borrow::Cow;
+use std::borrow::{Borrow, Cow};
 use std::{cmp, fmt};
 
 pub use GenericArgs::*;
@@ -155,6 +155,59 @@ impl Path {
     }
 }
 
+/// Joins multiple symbols with "::" into a path, e.g. "a::b::c". If the first
+/// segment is `kw::PathRoot` it will be printed as empty, e.g. "::b::c".
+///
+/// The generics on the `path` argument mean it can accept many forms, such as:
+/// - `&[Symbol]`
+/// - `Vec<Symbol>`
+/// - `Vec<&Symbol>`
+/// - `impl Iterator<Item = Symbol>`
+/// - `impl Iterator<Item = &Symbol>`
+///
+/// Panics if `path` is empty or a segment after the first is `kw::PathRoot`.
+pub fn join_path_syms(path: impl IntoIterator<Item = impl Borrow<Symbol>>) -> String {
+    // This is a guess at the needed capacity that works well in practice. It is slightly faster
+    // than (a) starting with an empty string, or (b) computing the exact capacity required.
+    // `8` works well because it's about the right size and jemalloc's size classes are all
+    // multiples of 8.
+    let mut iter = path.into_iter();
+    let len_hint = iter.size_hint().1.unwrap_or(1);
+    let mut s = String::with_capacity(len_hint * 8);
+
+    let first_sym = *iter.next().unwrap().borrow();
+    if first_sym != kw::PathRoot {
+        s.push_str(first_sym.as_str());
+    }
+    for sym in iter {
+        let sym = *sym.borrow();
+        debug_assert_ne!(sym, kw::PathRoot);
+        s.push_str("::");
+        s.push_str(sym.as_str());
+    }
+    s
+}
+
+/// Like `join_path_syms`, but for `Ident`s. This function is necessary because
+/// `Ident::to_string` does more than just print the symbol in the `name` field.
+pub fn join_path_idents(path: impl IntoIterator<Item = impl Borrow<Ident>>) -> String {
+    let mut iter = path.into_iter();
+    let len_hint = iter.size_hint().1.unwrap_or(1);
+    let mut s = String::with_capacity(len_hint * 8);
+
+    let first_ident = *iter.next().unwrap().borrow();
+    if first_ident.name != kw::PathRoot {
+        s.push_str(&first_ident.to_string());
+    }
+    for ident in iter {
+        let ident = *ident.borrow();
+        debug_assert_ne!(ident.name, kw::PathRoot);
+        s.push_str("::");
+        s.push_str(&ident.to_string());
+    }
+    s
+}
+
 /// A segment of a path: an identifier, an optional lifetime, and a set of types.
 ///
 /// E.g., `std`, `String` or `Box<T>`.
@@ -3637,6 +3690,7 @@ impl Default for FnHeader {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Trait {
+    pub constness: Const,
     pub safety: Safety,
     pub is_auto: IsAuto,
     pub ident: Ident,
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index fa7878873e5..2dfd695d880 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -126,11 +126,11 @@ impl LitKind {
             token::CStr => {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
-                unescape_c_str(s, |_span, c| match c {
+                unescape_c_str(s, |_span, res| match res {
                     Ok(MixedUnit::Char(c)) => {
-                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                        buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes())
                     }
-                    Ok(MixedUnit::HighByte(b)) => buf.push(b),
+                    Ok(MixedUnit::HighByte(b)) => buf.push(b.get()),
                     Err(err) => {
                         assert!(!err.is_fatal(), "failed to unescape C string literal")
                     }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 37fcc0d2167..a344f23c345 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -738,7 +738,8 @@ macro_rules! common_visitor_and_walkers {
                         try_visit!(vis.visit_ty(self_ty));
                         visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() })
                     }
-                    ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => {
+                    ItemKind::Trait(box Trait { constness, safety, is_auto: _, ident, generics, bounds, items }) => {
+                        try_visit!(visit_constness(vis, constness));
                         try_visit!(visit_safety(vis, safety));
                         try_visit!(vis.visit_ident(ident));
                         try_visit!(vis.visit_generics(generics));
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 9d40a7386f6..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> {
@@ -417,7 +414,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     items: new_impl_items,
                 }))
             }
-            ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => {
+            ItemKind::Trait(box Trait {
+                constness,
+                is_auto,
+                safety,
+                ident,
+                generics,
+                bounds,
+                items,
+            }) => {
+                let constness = self.lower_constness(*constness);
                 let ident = self.lower_ident(*ident);
                 let (generics, (safety, items, bounds)) = self.lower_generics(
                     generics,
@@ -426,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(
@@ -435,7 +442,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         (safety, items, bounds)
                     },
                 );
-                hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items)
+                hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
             }
             ItemKind::TraitAlias(ident, generics, bounds) => {
                 let ident = self.lower_ident(*ident);
@@ -446,6 +453,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     |this| {
                         this.lower_param_bounds(
                             bounds,
+                            RelaxedBoundPolicy::Allowed,
                             ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         )
                     },
@@ -931,6 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::TraitItemKind::Type(
                             this.lower_param_bounds(
                                 bounds,
+                                RelaxedBoundPolicy::Allowed,
                                 ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                             ),
                             ty,
@@ -1668,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(
@@ -1732,6 +1686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 &param.bounds,
                 param.colon_span,
                 generics.span,
+                RelaxedBoundPolicy::Allowed,
                 itctx,
                 PredicateOrigin::GenericParam,
             )
@@ -1741,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
@@ -1818,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>> {
@@ -1826,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;
 
@@ -1878,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);
@@ -1887,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(
@@ -1907,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 c5780c957c9..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
 
@@ -240,10 +235,10 @@ ast_passes_static_without_body =
 ast_passes_tilde_const_disallowed = `[const]` is not allowed here
     .closure = closures cannot have `[const]` trait bounds
     .function = this function is not `const`, so it cannot have `[const]` trait bounds
-    .trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+    .trait = this trait is not `const`, so it cannot have `[const]` trait bounds
     .trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds
     .impl = inherent impls cannot have `[const]` trait bounds
-    .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
+    .trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds
     .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
     .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
     .object = trait objects cannot have `[const]` trait bounds
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 38889d28151..a08dae11153 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -49,14 +49,14 @@ enum SelfSemantic {
 }
 
 enum TraitOrTraitImpl {
-    Trait { span: Span, constness_span: Option<Span> },
+    Trait { span: Span, constness: Const },
     TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
 }
 
 impl TraitOrTraitImpl {
     fn constness(&self) -> Option<Span> {
         match self {
-            Self::Trait { constness_span: Some(span), .. }
+            Self::Trait { constness: Const::Yes(span), .. }
             | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
             _ => None,
         }
@@ -110,15 +110,10 @@ impl<'a> AstValidator<'a> {
         self.outer_trait_or_trait_impl = old;
     }
 
-    fn with_in_trait(
-        &mut self,
-        span: Span,
-        constness_span: Option<Span>,
-        f: impl FnOnce(&mut Self),
-    ) {
+    fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(
             &mut self.outer_trait_or_trait_impl,
-            Some(TraitOrTraitImpl::Trait { span, constness_span }),
+            Some(TraitOrTraitImpl::Trait { span, constness }),
         );
         f(self);
         self.outer_trait_or_trait_impl = old;
@@ -273,7 +268,7 @@ impl<'a> AstValidator<'a> {
         };
 
         let make_trait_const_sugg = if const_trait_impl
-            && let TraitOrTraitImpl::Trait { span, constness_span: None } = parent
+            && let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent
         {
             Some(span.shrink_to_lo())
         } else {
@@ -1131,10 +1126,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 visit::walk_item(self, item)
             }
-            ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => {
+            ItemKind::Trait(box Trait {
+                constness,
+                is_auto,
+                generics,
+                ident,
+                bounds,
+                items,
+                ..
+            }) => {
                 self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
-                let is_const_trait =
+                // FIXME(const_trait_impl) remove this
+                let alt_const_trait_span =
                     attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
+                let constness = match (*constness, alt_const_trait_span) {
+                    (Const::Yes(span), _) | (Const::No, Some(span)) => Const::Yes(span),
+                    (Const::No, None) => Const::No,
+                };
                 if *is_auto == IsAuto::Yes {
                     // Auto traits cannot have generics, super traits nor contain items.
                     self.deny_generic_params(generics, ident.span);
@@ -1145,13 +1153,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
                 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
                 // context for the supertraits.
-                let disallowed =
-                    is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span });
+                let disallowed = matches!(constness, ast::Const::No)
+                    .then(|| TildeConstReason::Trait { span: item.span });
                 self.with_tilde_const(disallowed, |this| {
                     this.visit_generics(generics);
                     walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
                 });
-                self.with_in_trait(item.span, is_const_trait, |this| {
+                self.with_in_trait(item.span, constness, |this| {
                     walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
                 });
             }
@@ -1373,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 3b2730d4ff9..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]
@@ -590,7 +574,7 @@ pub(crate) struct ConstBoundTraitObject {
 }
 
 // FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic.
-// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
+// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` here).
 #[derive(Diagnostic)]
 #[diag(ast_passes_tilde_const_disallowed)]
 pub(crate) struct TildeConstDisallowed {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 6c442553976..11c97a552c6 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -357,6 +357,7 @@ impl<'a> State<'a> {
                 self.bclose(item.span, empty, cb);
             }
             ast::ItemKind::Trait(box ast::Trait {
+                constness,
                 safety,
                 is_auto,
                 ident,
@@ -366,6 +367,7 @@ impl<'a> State<'a> {
             }) => {
                 let (cb, ib) = self.head("");
                 self.print_visibility(&item.vis);
+                self.print_constness(*constness);
                 self.print_safety(*safety);
                 self.print_is_auto(*is_auto);
                 self.word_nbsp("trait");
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 3dedeb1b372..3157b18b635 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -110,6 +110,22 @@ pub enum DeprecatedSince {
     Err,
 }
 
+#[derive(
+    Copy,
+    Debug,
+    Eq,
+    PartialEq,
+    Encodable,
+    Decodable,
+    Clone,
+    HashStable_Generic,
+    PrintAttribute
+)]
+pub enum CoverageStatus {
+    On,
+    Off,
+}
+
 impl Deprecation {
     /// Whether an item marked with #[deprecated(since = "X")] is currently
     /// deprecated (i.e., whether X is not greater than the current rustc
@@ -274,6 +290,9 @@ pub enum AttributeKind {
     /// Represents `#[const_trait]`.
     ConstTrait(Span),
 
+    /// Represents `#[coverage]`.
+    Coverage(Span, CoverageStatus),
+
     ///Represents `#[rustc_deny_explicit_impl]`.
     DenyExplicitImpl(Span),
 
@@ -420,6 +439,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_unsafe_specialization_marker]`.
     UnsafeSpecializationMarker(Span),
 
+    /// Represents `#[unstable_feature_bound]`.
+    UnstableFeatureBound(ThinVec<(Symbol, Span)>),
+
     /// Represents `#[used]`
     Used { used_by: UsedBy, span: Span },
     // tidy-alphabetical-end
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 3e2dc0a15b2..86d9ddba4d2 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -28,6 +28,7 @@ impl AttributeKind {
             ConstStability { .. } => Yes,
             ConstStabilityIndirect => No,
             ConstTrait(..) => No,
+            Coverage(..) => No,
             DenyExplicitImpl(..) => No,
             Deprecation { .. } => Yes,
             DoNotImplementViaObject(..) => No,
@@ -40,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,
@@ -50,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,
@@ -71,6 +72,7 @@ impl AttributeKind {
             TrackCaller(..) => Yes,
             TypeConst(..) => Yes,
             UnsafeSpecializationMarker(..) => No,
+            UnstableFeatureBound(..) => No,
             Used { .. } => No,
             // tidy-alphabetical-end
         }
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index 8f8ce575a18..ecca0e39063 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -24,7 +24,7 @@ use rustc_ast::token::CommentKind;
 use rustc_ast::{AttrStyle, IntTy, UintTy};
 use rustc_ast_pretty::pp::Printer;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Span, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 pub use stability::*;
 use thin_vec::ThinVec;
 pub use version::*;
@@ -170,7 +170,7 @@ macro_rules! print_tup {
 }
 
 print_tup!(A B C D E F G H);
-print_skip!(Span, ());
+print_skip!(Span, (), ErrorGuaranteed);
 print_disp!(u16, bool, NonZero<u32>);
 print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
 
diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs
index 218e771c745..bd31c062117 100644
--- a/compiler/rustc_attr_data_structures/src/stability.rs
+++ b/compiler/rustc_attr_data_structures/src/stability.rs
@@ -1,7 +1,7 @@
 use std::num::NonZero;
 
 use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
-use rustc_span::{Symbol, sym};
+use rustc_span::{ErrorGuaranteed, Symbol, sym};
 
 use crate::{PrintAttribute, RustcVersion};
 
@@ -153,7 +153,7 @@ pub enum StableSince {
     /// Stabilized in the upcoming version, whatever number that is.
     Current,
     /// Failed to parse a stabilization version.
-    Err,
+    Err(ErrorGuaranteed),
 }
 
 impl StabilityLevel {
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 8d0ead63a8d..35ff48cb5f2 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -136,6 +136,9 @@ attr_parsing_unrecognized_repr_hint =
 attr_parsing_unstable_cfg_target_compact =
     compact `cfg(target(..))` is experimental and subject to change
 
+attr_parsing_unstable_feature_bound_incompatible_stability = Item annotated with `#[unstable_feature_bound]` should not be stable
+    .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
+
 attr_parsing_unsupported_literal_cfg_boolean =
     literal in `cfg` predicate value must be a boolean
 attr_parsing_unsupported_literal_cfg_string =
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 1c51c3eee4e..a6bd2306ec5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -27,6 +27,26 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
     }
 }
 
+pub(crate) struct UnstableFeatureBoundParser;
+impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
+    type Item = (Symbol, Span);
+    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
+
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> {
+        if !cx.features().staged_api() {
+            cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
+        }
+        parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
+            .into_iter()
+            .zip(iter::repeat(cx.attr_span))
+    }
+}
+
 pub(crate) struct AllowConstFnUnstableParser;
 impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index a56855b3bd3..6373cf6e08a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -9,7 +9,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
-use crate::context::{AcceptContext, Stage};
+use crate::context::{AcceptContext, ShouldEmit, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
 use crate::{
     CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
@@ -90,7 +90,7 @@ fn parse_cfg_entry_version<S: Stage>(
     list: &MetaItemListParser<'_>,
     meta_span: Span,
 ) -> Option<CfgEntry> {
-    try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features()));
+    try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option());
     let Some(version) = list.single() else {
         cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span });
         return None;
@@ -119,7 +119,9 @@ fn parse_cfg_entry_target<S: Stage>(
     list: &MetaItemListParser<'_>,
     meta_span: Span,
 ) -> Option<CfgEntry> {
-    if !cx.features().cfg_target_compact() {
+    if let Some(features) = cx.features_option()
+        && !features.cfg_target_compact()
+    {
         feature_err(
             cx.sess(),
             sym::cfg_target_compact,
@@ -186,12 +188,13 @@ pub fn eval_config_entry(
     cfg_entry: &CfgEntry,
     id: NodeId,
     features: Option<&Features>,
+    emit_lints: ShouldEmit,
 ) -> EvalConfigResult {
     match cfg_entry {
         CfgEntry::All(subs, ..) => {
             let mut all = None;
             for sub in subs {
-                let res = eval_config_entry(sess, sub, id, features);
+                let res = eval_config_entry(sess, sub, id, features, emit_lints);
                 // We cannot short-circuit because `eval_config_entry` emits some lints
                 if !res.as_bool() {
                     all.get_or_insert(res);
@@ -202,7 +205,7 @@ pub fn eval_config_entry(
         CfgEntry::Any(subs, span) => {
             let mut any = None;
             for sub in subs {
-                let res = eval_config_entry(sess, sub, id, features);
+                let res = eval_config_entry(sess, sub, id, features, emit_lints);
                 // We cannot short-circuit because `eval_config_entry` emits some lints
                 if res.as_bool() {
                     any.get_or_insert(res);
@@ -214,7 +217,7 @@ pub fn eval_config_entry(
             })
         }
         CfgEntry::Not(sub, span) => {
-            if eval_config_entry(sess, sub, id, features).as_bool() {
+            if eval_config_entry(sess, sub, id, features, emit_lints).as_bool() {
                 EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
             } else {
                 EvalConfigResult::True
@@ -228,24 +231,28 @@ pub fn eval_config_entry(
             }
         }
         CfgEntry::NameValue { name, name_span, value, span } => {
-            match sess.psess.check_config.expecteds.get(name) {
-                Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => {
-                    id.emit_span_lint(
-                        sess,
-                        UNEXPECTED_CFGS,
-                        *span,
-                        BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
-                    );
+            if let ShouldEmit::ErrorsAndLints = emit_lints {
+                match sess.psess.check_config.expecteds.get(name) {
+                    Some(ExpectedValues::Some(values))
+                        if !values.contains(&value.map(|(v, _)| v)) =>
+                    {
+                        id.emit_span_lint(
+                            sess,
+                            UNEXPECTED_CFGS,
+                            *span,
+                            BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
+                        );
+                    }
+                    None if sess.psess.check_config.exhaustive_names => {
+                        id.emit_span_lint(
+                            sess,
+                            UNEXPECTED_CFGS,
+                            *span,
+                            BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
+                        );
+                    }
+                    _ => { /* not unexpected */ }
                 }
-                None if sess.psess.check_config.exhaustive_names => {
-                    id.emit_span_lint(
-                        sess,
-                        UNEXPECTED_CFGS,
-                        *span,
-                        BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
-                    );
-                }
-                _ => { /* not unexpected */ }
             }
 
             if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 34d9b048348..3e542771d58 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -1,4 +1,4 @@
-use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
+use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
 use rustc_feature::{AttributeTemplate, template};
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
@@ -52,6 +52,45 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
 }
 
+pub(crate) struct CoverageParser;
+
+impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
+    const PATH: &[Symbol] = &[sym::coverage];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let Some(args) = args.list() else {
+            cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]);
+            return None;
+        };
+
+        let Some(arg) = args.single() else {
+            cx.expected_single_argument(args.span);
+            return None;
+        };
+
+        let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]);
+
+        let Some(arg) = arg.meta_item() else {
+            fail_incorrect_argument(args.span);
+            return None;
+        };
+
+        let status = match arg.path().word_sym() {
+            Some(sym::off) => CoverageStatus::Off,
+            Some(sym::on) => CoverageStatus::On,
+            None | Some(_) => {
+                fail_incorrect_argument(arg.span());
+                return None;
+            }
+        };
+
+        Some(AttributeKind::Coverage(cx.attr_span, status))
+    }
+}
+
 pub(crate) struct ExportNameParser;
 
 impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 6bccd0042a8..59337749c87 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -98,6 +98,16 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
             }
         }
 
+        if let Some((Stability { level: StabilityLevel::Stable { .. }, .. }, _)) = self.stability {
+            for other_attr in cx.all_attrs {
+                if other_attr.word_is(sym::unstable_feature_bound) {
+                    cx.emit_err(session_diagnostics::UnstableFeatureBoundIncompatibleStability {
+                        span: cx.target_span,
+                    });
+                }
+            }
+        }
+
         let (stability, span) = self.stability?;
 
         Some(AttributeKind::Stability { stability, span })
@@ -282,12 +292,12 @@ pub(crate) fn parse_stability<S: Stage>(
         } else if let Some(version) = parse_version(since) {
             StableSince::Version(version)
         } else {
-            cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
-            StableSince::Err
+            let err = cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
+            StableSince::Err(err)
         }
     } else {
-        cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span });
-        StableSince::Err
+        let err = cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span });
+        StableSince::Err(err)
     };
 
     match feature {
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index d5e088effd5..e69a533699b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -91,6 +91,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
 }
 
+// FIXME(const_trait_impl): remove this
 // Const traits
 
 pub(crate) struct ConstTraitParser;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 567341d1517..4d692d9562c 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -13,10 +13,13 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI
 use rustc_session::Session;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
-use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
+use crate::attributes::allow_unstable::{
+    AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
+};
 use crate::attributes::codegen_attrs::{
-    ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser,
-    OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
+    ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
+    OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
+    UsedParser,
 };
 use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
@@ -133,9 +136,11 @@ attribute_parsers!(
         Combine<AllowInternalUnstableParser>,
         Combine<ReprParser>,
         Combine<TargetFeatureParser>,
+        Combine<UnstableFeatureBoundParser>,
         // tidy-alphabetical-end
 
         // tidy-alphabetical-start
+        Single<CoverageParser>,
         Single<DeprecationParser>,
         Single<DummyParser>,
         Single<ExportNameParser>,
@@ -223,7 +228,7 @@ impl Stage for Early {
         sess: &'sess Session,
         diag: impl for<'x> Diagnostic<'x>,
     ) -> ErrorGuaranteed {
-        if self.emit_errors {
+        if self.emit_errors.should_emit() {
             sess.dcx().emit_err(diag)
         } else {
             sess.dcx().create_err(diag).delay_as_bug()
@@ -254,7 +259,7 @@ pub struct Early {
     /// Whether to emit errors or delay them as a bug
     /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
     /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
-    pub emit_errors: bool,
+    pub emit_errors: ShouldEmit,
 }
 /// used when parsing attributes during ast lowering
 pub struct Late;
@@ -449,6 +454,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             reason: AttributeParseErrorReason::ExpectedSpecificArgument {
                 possibilities,
                 strings: false,
+                list: false,
+            },
+        })
+    }
+
+    pub(crate) fn expected_specific_argument_and_list(
+        &self,
+        span: Span,
+        possibilities: Vec<&'static str>,
+    ) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
+                possibilities,
+                strings: false,
+                list: true,
             },
         })
     }
@@ -466,6 +490,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             reason: AttributeParseErrorReason::ExpectedSpecificArgument {
                 possibilities,
                 strings: true,
+                list: false,
             },
         })
     }
@@ -555,6 +580,25 @@ pub enum OmitDoc {
     Skip,
 }
 
+#[derive(Copy, Clone)]
+pub enum ShouldEmit {
+    /// The operation will emit errors and lints.
+    /// This is usually what you need.
+    ErrorsAndLints,
+    /// The operation will emit *not* errors and lints.
+    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
+    Nothing,
+}
+
+impl ShouldEmit {
+    pub fn should_emit(&self) -> bool {
+        match self {
+            ShouldEmit::ErrorsAndLints => true,
+            ShouldEmit::Nothing => false,
+        }
+    }
+}
+
 /// Context created once, for example as part of the ast lowering
 /// context, through which all attributes can be lowered.
 pub struct AttributeParser<'sess, S: Stage = Late> {
@@ -597,7 +641,7 @@ impl<'sess> AttributeParser<'sess, Early> {
             tools: Vec::new(),
             parse_only: Some(sym),
             sess,
-            stage: Early { emit_errors: false },
+            stage: Early { emit_errors: ShouldEmit::Nothing },
         };
         let mut parsed = p.parse_attribute_list(
             attrs,
@@ -620,7 +664,7 @@ impl<'sess> AttributeParser<'sess, Early> {
         target_span: Span,
         target_node_id: NodeId,
         features: Option<&'sess Features>,
-        emit_errors: bool,
+        emit_errors: ShouldEmit,
         parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
         template: &AttributeTemplate,
     ) -> T {
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index 2102a26108b..dc54cb6b840 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -95,7 +95,7 @@ pub use attributes::cfg_old::*;
 pub use attributes::util::{
     find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
 };
-pub use context::{AttributeParser, Early, Late, OmitDoc};
+pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit};
 pub use lints::emit_attribute_lint;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 97bf3d1c549..9a400e0fe10 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -504,6 +504,14 @@ pub(crate) struct UnrecognizedReprHint {
 }
 
 #[derive(Diagnostic)]
+#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
+#[help]
+pub(crate) struct UnstableFeatureBoundIncompatibleStability {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
 pub(crate) struct NakedFunctionIncompatibleAttribute {
     #[primary_span]
@@ -525,7 +533,9 @@ pub(crate) struct LinkOrdinalOutOfRange {
 
 pub(crate) enum AttributeParseErrorReason {
     ExpectedNoArgs,
-    ExpectedStringLiteral { byte_string: Option<Span> },
+    ExpectedStringLiteral {
+        byte_string: Option<Span>,
+    },
     ExpectedIntegerLiteral,
     ExpectedAtLeastOneArgument,
     ExpectedSingleArgument,
@@ -533,7 +543,12 @@ pub(crate) enum AttributeParseErrorReason {
     UnexpectedLiteral,
     ExpectedNameValue(Option<Symbol>),
     DuplicateKey(Symbol),
-    ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
+    ExpectedSpecificArgument {
+        possibilities: Vec<&'static str>,
+        strings: bool,
+        /// Should we tell the user to write a list when they didn't?
+        list: bool,
+    },
 }
 
 pub(crate) struct AttributeParseError {
@@ -607,7 +622,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                     format!("expected this to be of the form `{name} = \"...\"`"),
                 );
             }
-            AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => {
+            AttributeParseErrorReason::ExpectedSpecificArgument {
+                possibilities,
+                strings,
+                list: false,
+            } => {
                 let quote = if strings { '"' } else { '`' };
                 match possibilities.as_slice() {
                     &[] => {}
@@ -633,6 +652,38 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                     }
                 }
             }
+            AttributeParseErrorReason::ExpectedSpecificArgument {
+                possibilities,
+                strings,
+                list: true,
+            } => {
+                let quote = if strings { '"' } else { '`' };
+                match possibilities.as_slice() {
+                    &[] => {}
+                    &[x] => {
+                        diag.span_label(
+                            self.span,
+                            format!(
+                                "this attribute is only valid with {quote}{x}{quote} as an argument"
+                            ),
+                        );
+                    }
+                    [first, second] => {
+                        diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
+                    }
+                    [first @ .., second_to_last, last] => {
+                        let mut res = String::new();
+                        for i in first {
+                            res.push_str(&format!("{quote}{i}{quote}, "));
+                        }
+                        res.push_str(&format!(
+                            "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
+                        ));
+
+                        diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}"));
+                    }
+                }
+            }
         }
 
         let suggestions = self.template.suggestions(false, &name);
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index ca636a8c999..9bb96b94506 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -7,7 +8,7 @@ use rustc_infer::infer::{InferCtxt, SubregionOrigin};
 use rustc_infer::traits::query::type_op::DeeplyNormalize;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
+    self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions,
 };
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -70,10 +71,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
-        let QueryRegionConstraints { outlives } = query_constraints;
+        let QueryRegionConstraints { outlives, assumptions } = query_constraints;
+        let assumptions =
+            elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
 
         for &(predicate, constraint_category) in outlives {
-            self.convert(predicate, constraint_category);
+            self.convert(predicate, constraint_category, &assumptions);
         }
     }
 
@@ -112,15 +115,20 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
 
             self.category = outlives_requirement.category;
             self.span = outlives_requirement.blame_span;
-            self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category);
+            self.convert(
+                ty::OutlivesPredicate(subject, outlived_region),
+                self.category,
+                &Default::default(),
+            );
         }
         (self.category, self.span, self.from_closure) = backup;
     }
 
     fn convert(
         &mut self,
-        predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
+        predicate: ty::ArgOutlivesPredicate<'tcx>,
         constraint_category: ConstraintCategory<'tcx>,
+        higher_ranked_assumptions: &FxHashSet<ty::ArgOutlivesPredicate<'tcx>>,
     ) {
         let tcx = self.infcx.tcx;
         debug!("generate: constraints at: {:#?}", self.locations);
@@ -150,7 +158,15 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             }
 
             let mut next_outlives_predicates = vec![];
-            for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
+            for (pred, constraint_category) in outlives_predicates {
+                // Constraint is implied by a coroutine's well-formedness.
+                if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
+                    && higher_ranked_assumptions.contains(&pred)
+                {
+                    continue;
+                }
+
+                let ty::OutlivesPredicate(k1, r2) = pred;
                 match k1.kind() {
                     GenericArgKind::Lifetime(r1) => {
                         let r1_vid = self.to_region_vid(r1);
@@ -266,14 +282,15 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         &self,
         ty: Ty<'tcx>,
         next_outlives_predicates: &mut Vec<(
-            ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
+            ty::ArgOutlivesPredicate<'tcx>,
             ConstraintCategory<'tcx>,
         )>,
     ) -> Ty<'tcx> {
         match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
         {
             Ok(TypeOpOutput { output: ty, constraints, .. }) => {
-                if let Some(QueryRegionConstraints { outlives }) = constraints {
+                // FIXME(higher_ranked_auto): What should we do with the assumptions here?
+                if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
                     next_outlives_predicates.extend(outlives.iter().copied());
                 }
                 ty
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index f877e5eaadb..d500088c259 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -131,6 +131,11 @@ pub(crate) fn type_check<'tcx>(
         pre_obligations.is_empty(),
         "there should be no incoming region obligations = {pre_obligations:#?}",
     );
+    let pre_assumptions = infcx.take_registered_region_assumptions();
+    assert!(
+        pre_assumptions.is_empty(),
+        "there should be no incoming region assumptions = {pre_assumptions:#?}",
+    );
 
     debug!(?normalized_inputs_and_output);
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index a98e9c6d1c7..dd8f0e46a0e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -23,6 +23,7 @@ pub(crate) fn expand_deriving_copy(
         methods: Vec::new(),
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     trait_def.expand(cx, mitem, item, push);
@@ -46,6 +47,7 @@ pub(crate) fn expand_deriving_const_param_ty(
         methods: Vec::new(),
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     trait_def.expand(cx, mitem, item, push);
@@ -60,6 +62,7 @@ pub(crate) fn expand_deriving_const_param_ty(
         methods: Vec::new(),
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     trait_def.expand(cx, mitem, item, push);
@@ -83,6 +86,7 @@ pub(crate) fn expand_deriving_unsized_const_param_ty(
         methods: Vec::new(),
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     trait_def.expand(cx, mitem, item, push);
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 69f8c273797..3c78f53c5cb 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -87,6 +87,7 @@ pub(crate) fn expand_deriving_clone(
         }],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     trait_def.expand_ext(cx, mitem, item, push, is_simple)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index eca79e4dc48..29d531219a6 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -43,6 +43,7 @@ pub(crate) fn expand_deriving_eq(
         }],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
     trait_def.expand_ext(cx, mitem, item, push, true)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 1ed44c20bc6..0e1ecf3118a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -34,6 +34,7 @@ pub(crate) fn expand_deriving_ord(
         }],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     trait_def.expand(cx, mitem, item, push)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index b1d950b8d89..990835fa277 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -30,6 +30,7 @@ pub(crate) fn expand_deriving_partial_eq(
         methods: Vec::new(),
         associated_types: Vec::new(),
         is_const: false,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
     structural_trait_def.expand(cx, mitem, item, push);
 
@@ -58,6 +59,7 @@ pub(crate) fn expand_deriving_partial_eq(
         methods,
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 0a076dd670b..f5d262ece36 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -64,6 +64,7 @@ pub(crate) fn expand_deriving_partial_ord(
         methods: vec![partial_cmp_def],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 8ab21986e68..1d63ce7d5fd 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_debug(
         }],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 1fe567e23f4..b4e2d27fed3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -51,6 +51,7 @@ pub(crate) fn expand_deriving_default(
         }],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index c55a9e73e38..b24e5563761 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -181,9 +181,11 @@ use std::{iter, vec};
 pub(crate) use StaticFields::*;
 pub(crate) use SubstructureFields::*;
 use rustc_ast::ptr::P;
+use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind};
+use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree};
 use rustc_ast::{
-    self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind,
-    Generics, Mutability, PatKind, VariantData,
+    self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg,
+    GenericParamKind, Generics, Mutability, PatKind, Safety, VariantData,
 };
 use rustc_attr_data_structures::{AttributeKind, ReprPacked};
 use rustc_attr_parsing::AttributeParser;
@@ -222,6 +224,8 @@ pub(crate) struct TraitDef<'a> {
     pub associated_types: Vec<(Ident, Ty)>,
 
     pub is_const: bool,
+
+    pub is_staged_api_crate: bool,
 }
 
 pub(crate) struct MethodDef<'a> {
@@ -784,8 +788,45 @@ impl<'a> TraitDef<'a> {
         // Create the type of `self`.
         let path = cx.path_all(self.span, false, vec![type_ident], self_params);
         let self_type = cx.ty_path(path);
+        let rustc_const_unstable =
+            cx.path_ident(self.span, Ident::new(sym::rustc_const_unstable, self.span));
+
+        let mut attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),];
+
+        // Only add `rustc_const_unstable` attributes if `derive_const` is used within libcore/libstd,
+        // Other crates don't need stability attributes, so adding them is not useful, but libcore needs them
+        // on all const trait impls.
+        if self.is_const && self.is_staged_api_crate {
+            attrs.push(
+                cx.attr_nested(
+                    rustc_ast::AttrItem {
+                        unsafety: Safety::Default,
+                        path: rustc_const_unstable,
+                        args: AttrArgs::Delimited(DelimArgs {
+                            dspan: DelimSpan::from_single(self.span),
+                            delim: rustc_ast::token::Delimiter::Parenthesis,
+                            tokens: [
+                                TokenKind::Ident(sym::feature, IdentIsRaw::No),
+                                TokenKind::Eq,
+                                TokenKind::lit(LitKind::Str, sym::derive_const, None),
+                                TokenKind::Comma,
+                                TokenKind::Ident(sym::issue, IdentIsRaw::No),
+                                TokenKind::Eq,
+                                TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
+                            ]
+                            .into_iter()
+                            .map(|kind| {
+                                TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone)
+                            })
+                            .collect(),
+                        }),
+                        tokens: None,
+                    },
+                    self.span,
+                ),
+            )
+        }
 
-        let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),];
         let opt_trait_ref = Some(trait_ref);
 
         cx.item(
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index 6e6dbe19e4d..78534449895 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_hash(
         }],
         associated_types: Vec::new(),
         is_const,
+        is_staged_api_crate: cx.ecfg.features.staged_api(),
     };
 
     hash_trait_def.expand(cx, mitem, item, push);
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index cebfffa1e16..ecfd46a84ec 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -4,8 +4,8 @@ use std::sync::Arc;
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{join_path_idents, token};
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::{
     DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path,
@@ -100,7 +100,7 @@ pub(crate) fn expand_mod(
     let sp = cx.with_def_site_ctxt(sp);
     check_zero_tts(cx, sp, tts, "module_path!");
     let mod_path = &cx.current_expansion.module.mod_path;
-    let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
+    let string = join_path_idents(mod_path);
 
     ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
 }
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index b067578794b..ba3d8368b2a 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -5,7 +5,7 @@ use std::assert_matches::assert_matches;
 use std::iter;
 
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, GenericParamKind, attr};
+use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, Diag, Level};
 use rustc_expand::base::*;
@@ -446,12 +446,7 @@ fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize,
 }
 
 fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String {
-    mod_path
-        .iter()
-        .chain(iter::once(item_ident))
-        .map(|x| x.to_string())
-        .collect::<Vec<String>>()
-        .join("::")
+    join_path_idents(mod_path.iter().chain(iter::once(item_ident)))
 }
 
 enum ShouldPanic {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 442151fe32d..8ec3599b63d 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -530,8 +530,8 @@ fn codegen_cgu_content(
     for (mono_item, item_data) in mono_items {
         match mono_item {
             MonoItem::Fn(instance) => {
-                if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED)
-                {
+                let flags = tcx.codegen_instance_attrs(instance.def).flags;
+                if flags.contains(CodegenFnAttrFlags::NAKED) {
                     rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
                         &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
                         instance,
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index b1f185b551c..b3497503bf0 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -127,7 +127,7 @@ fn codegen_and_compile_fn<'tcx>(
     module: &mut dyn Module,
     instance: Instance<'tcx>,
 ) {
-    if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
+    if tcx.codegen_instance_attrs(instance.def).flags.contains(CodegenFnAttrFlags::NAKED) {
         tcx.dcx()
             .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode");
     }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index ffd47cace38..8f83c30b598 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -35,7 +35,7 @@ fn predefine_mono_items<'tcx>(
                         is_compiler_builtins,
                     );
                     let is_naked = tcx
-                        .codegen_fn_attrs(instance.def_id())
+                        .codegen_instance_attrs(instance.def)
                         .flags
                         .contains(CodegenFnAttrFlags::NAKED);
                     module
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
index 245bee7f2a3..759d0d59e26 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
@@ -14,8 +14,6 @@ permissions:
 env:
   # Enable backtraces for easier debugging
   RUST_BACKTRACE: 1
-  # TODO: remove when confish.sh is removed.
-  OVERWRITE_TARGET_TRIPLE: m68k-unknown-linux-gnu
 
 jobs:
   build:
@@ -59,14 +57,12 @@ jobs:
 
     - name: Setup path to libgccjit
       run: |
-          sudo dpkg -i gcc-m68k-15.deb
+          sudo dpkg --force-overwrite -i gcc-m68k-15.deb
           echo 'gcc-path = "/usr/lib/"' > config.toml
 
     - name: Set env
       run: |
         echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
-        
-        
 
     #- name: Cache rust repository
       ## We only clone the rust repository for rustc tests
@@ -86,16 +82,20 @@ jobs:
     - name: Build sample project with target defined as JSON spec
       run: |
         ./y.sh prepare --only-libcore --cross
-        ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
-        ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
+        ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
+        CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json
         ./y.sh clean all
 
     - name: Build
       run: |
         ./y.sh prepare --only-libcore --cross
-        ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu
-        ./y.sh test --mini-tests
-        CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests
+        ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu
+        ./y.sh test --mini-tests --target-triple m68k-unknown-linux-gnu
+        # FIXME: since https://github.com/rust-lang/rust/pull/140809, we cannot run programs for architectures not
+        # supported by the object crate, since this adds a dependency on symbols.o for the panic runtime.
+        # And as such, a wrong order of the object files in the linker command now fails with an undefined reference
+        # to some symbols like __rustc::rust_panic.
+        #CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu
         ./y.sh clean all
 
     - name: Prepare dependencies
@@ -104,9 +104,23 @@ jobs:
         git config --global user.name "User"
         ./y.sh prepare --cross
 
-    - name: Run tests
-      run: |
-        ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }}
+    # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above.
+    #- name: Run tests
+      #run: |
+        #./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler-builtins-no-f16-f128 ${{ matrix.commands }}
+
+    # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above.
+    #- name: Run Hello World!
+      #run: |
+        #./y.sh build --target-triple m68k-unknown-linux-gnu
+
+        #vm_dir=$(pwd)/vm
+        #cd tests/hello-world
+        #CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu
+        #sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/
+        #sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout
+        #expected_output="40"
+        #test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1)
 
   # Summary job for the merge queue.
   # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
index 1d8eaf9a141..b7e2583aad3 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
@@ -78,7 +78,8 @@ jobs:
     - name: Run tests
       run: |
         # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros.
-        echo -n 'lto = "fat"' >> build_system/build_sysroot/Cargo.toml
+        # FIXME(antoyo): this should probably not be needed since we embed the LTO bitcode.
+        printf '[profile.release]\nlto = "fat"\n' >> build/build_sysroot/sysroot_src/library/Cargo.toml
         EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }}
 
     - name: Run y.sh cargo build
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
deleted file mode 100644
index 0c75977ee79..00000000000
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
+++ /dev/null
@@ -1,502 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "addr2line"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
-dependencies = [
- "compiler_builtins",
- "gimli",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "adler2"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "alloc"
-version = "0.0.0"
-dependencies = [
- "compiler_builtins",
- "core",
-]
-
-[[package]]
-name = "alloctests"
-version = "0.0.0"
-dependencies = [
- "rand",
- "rand_xorshift",
-]
-
-[[package]]
-name = "cc"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
-dependencies = [
- "shlex",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "compiler_builtins"
-version = "0.1.160"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895"
-dependencies = [
- "cc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "core"
-version = "0.0.0"
-
-[[package]]
-name = "coretests"
-version = "0.0.0"
-dependencies = [
- "rand",
- "rand_xorshift",
-]
-
-[[package]]
-name = "dlmalloc"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "libc",
- "rustc-std-workspace-core",
- "windows-sys",
-]
-
-[[package]]
-name = "fortanix-sgx-abi"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "getopts"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
-dependencies = [
- "rustc-std-workspace-core",
- "rustc-std-workspace-std",
- "unicode-width",
-]
-
-[[package]]
-name = "gimli"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.15.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "hermit-abi"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.172"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
-dependencies = [
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "memchr"
-version = "2.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "miniz_oxide"
-version = "0.8.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
-dependencies = [
- "adler2",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "object"
-version = "0.36.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
-dependencies = [
- "compiler_builtins",
- "memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "panic_abort"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "compiler_builtins",
- "core",
- "libc",
-]
-
-[[package]]
-name = "panic_unwind"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
- "unwind",
-]
-
-[[package]]
-name = "proc_macro"
-version = "0.0.0"
-dependencies = [
- "core",
- "rustc-literal-escaper",
- "std",
-]
-
-[[package]]
-name = "profiler_builtins"
-version = "0.0.0"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "r-efi"
-version = "5.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "r-efi-alloc"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
-dependencies = [
- "compiler_builtins",
- "r-efi",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "rand"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
-
-[[package]]
-name = "rand_xorshift"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "rustc-literal-escaper"
-version = "0.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
-dependencies = [
- "rustc-std-workspace-std",
-]
-
-[[package]]
-name = "rustc-std-workspace-alloc"
-version = "1.99.0"
-dependencies = [
- "alloc",
-]
-
-[[package]]
-name = "rustc-std-workspace-core"
-version = "1.99.0"
-dependencies = [
- "core",
-]
-
-[[package]]
-name = "rustc-std-workspace-std"
-version = "1.99.0"
-dependencies = [
- "std",
-]
-
-[[package]]
-name = "shlex"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
-[[package]]
-name = "std"
-version = "0.0.0"
-dependencies = [
- "addr2line",
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "dlmalloc",
- "fortanix-sgx-abi",
- "hashbrown",
- "hermit-abi",
- "libc",
- "miniz_oxide",
- "object",
- "panic_abort",
- "panic_unwind",
- "r-efi",
- "r-efi-alloc",
- "rand",
- "rand_xorshift",
- "rustc-demangle",
- "std_detect",
- "unwind",
- "wasi",
- "windows-targets 0.0.0",
-]
-
-[[package]]
-name = "std_detect"
-version = "0.1.5"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "libc",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "sysroot"
-version = "0.0.0"
-dependencies = [
- "proc_macro",
- "profiler_builtins",
- "std",
- "test",
-]
-
-[[package]]
-name = "test"
-version = "0.0.0"
-dependencies = [
- "core",
- "getopts",
- "libc",
- "std",
-]
-
-[[package]]
-name = "unicode-width"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
- "rustc-std-workspace-std",
-]
-
-[[package]]
-name = "unwind"
-version = "0.0.0"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
- "unwinding",
-]
-
-[[package]]
-name = "unwinding"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345"
-dependencies = [
- "compiler_builtins",
- "gimli",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.0.0"
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
deleted file mode 100644
index 29a3bcec304..00000000000
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-[package]
-authors = ["rustc_codegen_gcc devs"]
-name = "sysroot"
-version = "0.0.0"
-resolver = "2"
-
-[dependencies]
-core = { path = "./sysroot_src/library/core" }
-compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" }
-alloc = { path = "./sysroot_src/library/alloc" }
-std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
-test = { path = "./sysroot_src/library/test" }
-proc_macro = { path = "./sysroot_src/library/proc_macro" }
-
-[patch.crates-io]
-rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
-rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
-rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
-compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" }
-
-# For compiler-builtins we always use a high number of codegen units.
-# The goal here is to place every single intrinsic into its own object
-# file to avoid symbol clashes with the system libgcc if possible. Note
-# that this number doesn't actually produce this many object files, we
-# just don't create more than this number of object files.
-#
-# It's a bit of a bummer that we have to pass this here, unfortunately.
-# Ideally this would be specified through an env var to Cargo so Cargo
-# knows how many CGUs are for this specific crate, but for now
-# per-crate configuration isn't specifiable in the environment.
-[profile.dev.package.compiler_builtins]
-codegen-units = 10000
-
-[profile.release.package.compiler_builtins]
-codegen-units = 10000
-
-[profile.release]
-debug = "limited"
-#lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed.
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/lib.rs b/compiler/rustc_codegen_gcc/build_system/build_sysroot/lib.rs
deleted file mode 100644
index 0c9ac1ac8e4..00000000000
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/lib.rs
+++ /dev/null
@@ -1 +0,0 @@
-#![no_std]
diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs
index ecc4c1b2fe2..94b40319f4a 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/build.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs
@@ -5,7 +5,7 @@ use std::path::Path;
 
 use crate::config::{Channel, ConfigInfo};
 use crate::utils::{
-    copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir,
+    create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir,
 };
 
 #[derive(Default)]
@@ -53,11 +53,11 @@ impl BuildArg {
     }
 }
 
-fn cleanup_sysroot_previous_build(start_dir: &Path) {
+fn cleanup_sysroot_previous_build(library_dir: &Path) {
     // Cleanup for previous run
     // Clean target dir except for build scripts and incremental cache
     let _ = walk_dir(
-        start_dir.join("target"),
+        library_dir.join("target"),
         &mut |dir: &Path| {
             for top in &["debug", "release"] {
                 let _ = fs::remove_dir_all(dir.join(top).join("build"));
@@ -95,31 +95,13 @@ fn cleanup_sysroot_previous_build(start_dir: &Path) {
         &mut |_| Ok(()),
         false,
     );
-
-    let _ = fs::remove_file(start_dir.join("Cargo.lock"));
-    let _ = fs::remove_file(start_dir.join("test_target/Cargo.lock"));
-    let _ = fs::remove_dir_all(start_dir.join("sysroot"));
-}
-
-pub fn create_build_sysroot_content(start_dir: &Path) -> Result<(), String> {
-    if !start_dir.is_dir() {
-        create_dir(start_dir)?;
-    }
-    copy_file("build_system/build_sysroot/Cargo.toml", start_dir.join("Cargo.toml"))?;
-    copy_file("build_system/build_sysroot/Cargo.lock", start_dir.join("Cargo.lock"))?;
-
-    let src_dir = start_dir.join("src");
-    if !src_dir.is_dir() {
-        create_dir(&src_dir)?;
-    }
-    copy_file("build_system/build_sysroot/lib.rs", start_dir.join("src/lib.rs"))
 }
 
 pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Result<(), String> {
     let start_dir = get_sysroot_dir();
 
-    cleanup_sysroot_previous_build(&start_dir);
-    create_build_sysroot_content(&start_dir)?;
+    let library_dir = start_dir.join("sysroot_src").join("library");
+    cleanup_sysroot_previous_build(&library_dir);
 
     // Builds libs
     let mut rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default();
@@ -157,9 +139,13 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
         rustflags.push_str(&cg_rustflags);
     }
 
+    args.push(&"--features");
+    args.push(&"backtrace");
+
     let mut env = env.clone();
     env.insert("RUSTFLAGS".to_string(), rustflags);
-    run_command_with_output_and_env(&args, Some(&start_dir), Some(&env))?;
+    let sysroot_dir = library_dir.join("sysroot");
+    run_command_with_output_and_env(&args, Some(&sysroot_dir), Some(&env))?;
 
     // Copy files to sysroot
     let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple));
@@ -169,7 +155,7 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
         run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
     };
     walk_dir(
-        start_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)),
+        library_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)),
         &mut copier.clone(),
         &mut copier,
         false,
@@ -178,7 +164,7 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
     // Copy the source files to the sysroot (Rust for Linux needs this).
     let sysroot_src_path = start_dir.join("sysroot/lib/rustlib/src/rust");
     create_dir(&sysroot_src_path)?;
-    run_command(&[&"cp", &"-r", &start_dir.join("sysroot_src/library/"), &sysroot_src_path], None)?;
+    run_command(&[&"cp", &"-r", &library_dir, &sysroot_src_path], None)?;
 
     Ok(())
 }
diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs
index 650c030ca53..a5f802e293a 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/config.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs
@@ -352,11 +352,6 @@ impl ConfigInfo {
             None => return Err("no host found".to_string()),
         };
 
-        if self.target_triple.is_empty()
-            && let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE")
-        {
-            self.target_triple = overwrite.clone();
-        }
         if self.target_triple.is_empty() {
             self.target_triple = self.host_triple.clone();
         }
diff --git a/compiler/rustc_codegen_gcc/build_system/src/utils.rs b/compiler/rustc_codegen_gcc/build_system/src/utils.rs
index d77707d5f17..fc948c54b24 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/utils.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/utils.rs
@@ -303,19 +303,6 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> Result<(), String> {
     })
 }
 
-pub fn copy_file<F: AsRef<Path>, T: AsRef<Path>>(from: F, to: T) -> Result<(), String> {
-    fs::copy(&from, &to)
-        .map_err(|error| {
-            format!(
-                "Failed to copy file `{}` into `{}`: {:?}",
-                from.as_ref().display(),
-                to.as_ref().display(),
-                error
-            )
-        })
-        .map(|_| ())
-}
-
 /// This function differs from `git_clone` in how it handles *where* the repository will be cloned.
 /// In `git_clone`, it is cloned in the provided path. In this function, the path you provide is
 /// the parent folder. So if you pass "a" as folder and try to clone "b.git", it will be cloned into
diff --git a/compiler/rustc_codegen_gcc/doc/tips.md b/compiler/rustc_codegen_gcc/doc/tips.md
index 86c22db186e..e62c3402a29 100644
--- a/compiler/rustc_codegen_gcc/doc/tips.md
+++ b/compiler/rustc_codegen_gcc/doc/tips.md
@@ -62,14 +62,14 @@ generate it in [gimple.md](./doc/gimple.md).
 
  * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case.
  * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`).
- * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`.
- * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`.
+ * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. You can specify which linker to use via `CG_RUSTFLAGS="-Clinker=<linker>"`, for instance: `CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc"`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`.
+ * Build your project by specifying the target and the linker to use: `CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../y.sh cargo build --target m68k-unknown-linux-gnu`.
 
 If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler).
 Then, you can use it the following way:
 
  * Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json`
- * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`.
+ * Build your project by specifying the target specification file: `../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`.
 
 If you get the following error:
 
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 6b6f71edaf8..85489f850e2 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -6,7 +6,7 @@
 )]
 #![no_core]
 #![allow(dead_code, internal_features, non_camel_case_types)]
-#![rustfmt::skip]
+#![rustfmt_skip]
 
 extern crate mini_core;
 
@@ -198,10 +198,17 @@ fn main() {
         assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
         assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
 
-        assert!(!const { intrinsics::needs_drop::<u8>() });
-        assert!(!const { intrinsics::needs_drop::<[u8]>() });
-        assert!(const { intrinsics::needs_drop::<NoisyDrop>() });
-        assert!(const { intrinsics::needs_drop::<NoisyDropUnsized>() });
+        /*
+         * TODO: re-enable in the next sync.
+        let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
+        assert!(!u8_needs_drop);
+        let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() };
+        assert!(!slice_needs_drop);
+        let noisy_drop = const { intrinsics::needs_drop::<NoisyDrop>() };
+        assert!(noisy_drop);
+        let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
+        assert!(noisy_unsized_drop);
+        */
 
         Unique {
             pointer: 0 as *const &str,
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
index bccbc6cd2c5..2fe8ec4647f 100644
--- a/compiler/rustc_codegen_gcc/rust-toolchain
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2025-06-28"
+channel = "nightly-2025-07-04"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index bf0927dc590..7a1ae6ca9c8 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -87,7 +87,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
     #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>,
     instance: ty::Instance<'tcx>,
 ) {
-    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
+    let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def);
 
     #[cfg(feature = "master")]
     {
diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs
index 10fce860b77..e554dd2500b 100644
--- a/compiler/rustc_codegen_gcc/src/back/lto.rs
+++ b/compiler/rustc_codegen_gcc/src/back/lto.rs
@@ -24,7 +24,7 @@ use std::sync::Arc;
 
 use gccjit::{Context, OutputKind};
 use object::read::archive::ArchiveFile;
-use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
+use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
 use rustc_codegen_ssa::traits::*;
@@ -176,7 +176,7 @@ pub(crate) fn run_fat(
     cgcx: &CodegenContext<GccCodegenBackend>,
     modules: Vec<FatLtoInput<GccCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
-) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
+) -> Result<ModuleCodegen<GccContext>, FatalError> {
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
     let lto_data = prepare_lto(cgcx, dcx)?;
@@ -201,7 +201,7 @@ fn fat_lto(
     mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
     //symbols_below_threshold: &[String],
-) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
+) -> Result<ModuleCodegen<GccContext>, FatalError> {
     let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
     info!("going for a fat lto");
 
@@ -334,7 +334,7 @@ fn fat_lto(
     // of now.
     module.module_llvm.temp_dir = Some(tmp_path);
 
-    Ok(LtoModuleCodegen::Fat(module))
+    Ok(module)
 }
 
 pub struct ModuleBuffer(PathBuf);
@@ -358,7 +358,7 @@ pub(crate) fn run_thin(
     cgcx: &CodegenContext<GccCodegenBackend>,
     modules: Vec<(String, ThinBuffer)>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
-) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
+) -> Result<(Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
     let lto_data = prepare_lto(cgcx, dcx)?;
@@ -427,7 +427,7 @@ fn thin_lto(
     tmp_path: TempDir,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     //_symbols_below_threshold: &[String],
-) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
+) -> Result<(Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
     let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis");
     info!("going for that thin, thin LTO");
 
@@ -573,8 +573,7 @@ fn thin_lto(
         }*/
 
         info!(" - {}: re-compiled", module_name);
-        opt_jobs
-            .push(LtoModuleCodegen::Thin(ThinModule { shared: shared.clone(), idx: module_index }));
+        opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index });
     }
 
     // Save the current ThinLTO import information for the next compilation
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index d03d063bdac..113abe70805 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -16,10 +16,12 @@ use crate::{GccCodegenBackend, GccContext};
 
 pub(crate) fn codegen(
     cgcx: &CodegenContext<GccCodegenBackend>,
-    dcx: DiagCtxtHandle<'_>,
     module: ModuleCodegen<GccContext>,
     config: &ModuleConfig,
 ) -> Result<CompiledModule, FatalError> {
+    let dcx = cgcx.create_dcx();
+    let dcx = dcx.handle();
+
     let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name);
     {
         let context = &module.module_llvm.context;
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 28d1ec7d895..a4ec4bf8dea 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -971,7 +971,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
 
     fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
         let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer());
-        ptr.dereference(self.location).to_rvalue()
+        // (FractalFir): We insert a local here, to ensure this volatile load can't move across
+        // blocks.
+        let local = self.current_func().new_local(self.location, ty, "volatile_tmp");
+        self.block.add_assignment(self.location, local, ptr.dereference(self.location).to_rvalue());
+        local.to_rvalue()
     }
 
     fn atomic_load(
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
index 189ac7cd779..e7ca95af594 100644
--- a/compiler/rustc_codegen_gcc/src/callee.rs
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -105,7 +105,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
             let is_hidden = if is_generic {
                 // This is a monomorphization of a generic function.
                 if !(cx.tcx.sess.opts.share_generics()
-                    || tcx.codegen_fn_attrs(instance_def_id).inline
+                    || tcx.codegen_instance_attrs(instance.def).inline
                         == rustc_attr_data_structures::InlineAttr::Never)
                 {
                     // When not sharing generics, all instances are in the same
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index d8fae1ca47d..af416929ea7 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -93,7 +93,7 @@ use gccjit::{CType, Context, OptimizationLevel};
 use gccjit::{TargetInfo, Version};
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
-use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
+use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
 use rustc_codegen_ssa::back::write::{
     CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
 };
@@ -273,6 +273,10 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> {
 }
 
 impl ExtraBackendMethods for GccCodegenBackend {
+    fn supports_parallel(&self) -> bool {
+        false
+    }
+
     fn codegen_allocator(
         &self,
         tcx: TyCtxt<'_>,
@@ -341,8 +345,7 @@ impl Deref for SyncContext {
 }
 
 unsafe impl Send for SyncContext {}
-// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm".
-// TODO: disable it here by returning false in CodegenBackend::supports_parallel().
+// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "CodegenBackend::supports_parallel()".
 unsafe impl Sync for SyncContext {}
 
 impl WriteBackendMethods for GccCodegenBackend {
@@ -353,11 +356,16 @@ impl WriteBackendMethods for GccCodegenBackend {
     type ThinData = ThinData;
     type ThinBuffer = ThinBuffer;
 
-    fn run_fat_lto(
+    fn run_and_optimize_fat_lto(
         cgcx: &CodegenContext<Self>,
         modules: Vec<FatLtoInput<Self>>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
-    ) -> Result<LtoModuleCodegen<Self>, FatalError> {
+        diff_fncs: Vec<AutoDiffItem>,
+    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        if !diff_fncs.is_empty() {
+            unimplemented!();
+        }
+
         back::lto::run_fat(cgcx, modules, cached_modules)
     }
 
@@ -365,7 +373,7 @@ impl WriteBackendMethods for GccCodegenBackend {
         cgcx: &CodegenContext<Self>,
         modules: Vec<(String, Self::ThinBuffer)>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
-    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
+    ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError> {
         back::lto::run_thin(cgcx, modules, cached_modules)
     }
 
@@ -387,14 +395,6 @@ impl WriteBackendMethods for GccCodegenBackend {
         Ok(())
     }
 
-    fn optimize_fat(
-        _cgcx: &CodegenContext<Self>,
-        _module: &mut ModuleCodegen<Self::Module>,
-    ) -> Result<(), FatalError> {
-        // TODO(antoyo)
-        Ok(())
-    }
-
     fn optimize_thin(
         cgcx: &CodegenContext<Self>,
         thin: ThinModule<Self>,
@@ -404,11 +404,10 @@ impl WriteBackendMethods for GccCodegenBackend {
 
     fn codegen(
         cgcx: &CodegenContext<Self>,
-        dcx: DiagCtxtHandle<'_>,
         module: ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<CompiledModule, FatalError> {
-        back::write::codegen(cgcx, dcx, module, config)
+        back::write::codegen(cgcx, module, config)
     }
 
     fn prepare_thin(
@@ -429,15 +428,6 @@ impl WriteBackendMethods for GccCodegenBackend {
     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         back::write::link(cgcx, dcx, modules)
     }
-
-    fn autodiff(
-        _cgcx: &CodegenContext<Self>,
-        _module: &ModuleCodegen<Self::Module>,
-        _diff_functions: Vec<AutoDiffItem>,
-        _config: &ModuleConfig,
-    ) -> Result<(), FatalError> {
-        unimplemented!()
-    }
 }
 
 /// This is the entrypoint for a hot plugged rustc_codegen_gccjit
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index 539e3ac8507..ff188c437da 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -53,7 +53,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         self.linkage.set(base::linkage_to_gcc(linkage));
         let decl = self.declare_fn(symbol_name, fn_abi);
-        //let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+        //let attrs = self.tcx.codegen_instance_attrs(instance.def);
 
         attributes::from_fn_attrs(self, decl, instance);
 
@@ -64,7 +64,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) {
             #[cfg(feature = "master")]
             decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
-        } else {
+        } else if visibility != Visibility::Default {
             #[cfg(feature = "master")]
             decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility)));
         }
diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
index 544d0bfc710..6979c04d534 100644
--- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
+++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
@@ -80,3 +80,5 @@ tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
 tests/ui/coroutine/panic-drops-resume.rs
 tests/ui/coroutine/panic-drops.rs
 tests/ui/coroutine/panic-safe.rs
+tests/ui/process/nofile-limit.rs
+tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 2dbf43be664..9b15a28d829 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -16,6 +16,7 @@ add_asm:
      ret"
 );
 
+#[cfg(target_arch = "x86_64")]
 extern "C" {
     fn add_asm(a: i64, b: i64) -> i64;
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/float.rs b/compiler/rustc_codegen_gcc/tests/run/float.rs
index 424fa1cf4ad..df555f383fe 100644
--- a/compiler/rustc_codegen_gcc/tests/run/float.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/float.rs
@@ -3,8 +3,6 @@
 // Run-time:
 //   status: 0
 
-#![feature(const_black_box)]
-
 fn main() {
     use std::hint::black_box;
 
@@ -15,14 +13,14 @@ fn main() {
         }};
     }
 
-    check!(i32, (black_box(0.0f32) as i32));
+    check!(i32, black_box(0.0f32) as i32);
 
-    check!(u64, (black_box(f32::NAN) as u64));
-    check!(u128, (black_box(f32::NAN) as u128));
+    check!(u64, black_box(f32::NAN) as u64);
+    check!(u128, black_box(f32::NAN) as u128);
 
-    check!(i64, (black_box(f64::NAN) as i64));
-    check!(u64, (black_box(f64::NAN) as u64));
+    check!(i64, black_box(f64::NAN) as i64);
+    check!(u64, black_box(f64::NAN) as u64);
 
-    check!(i16, (black_box(f32::MIN) as i16));
-    check!(i16, (black_box(f32::MAX) as i16));
+    check!(i16, black_box(f32::MIN) as i16);
+    check!(i16, black_box(f32::MAX) as i16);
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index 47b5dea46f8..e20ecc23679 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,8 +3,6 @@
 // Run-time:
 //   status: 0
 
-#![feature(const_black_box)]
-
 fn main() {
     use std::hint::black_box;
 
diff --git a/compiler/rustc_codegen_gcc/tests/run/volatile.rs b/compiler/rustc_codegen_gcc/tests/run/volatile.rs
index 8b043312593..94a7bdc5c06 100644
--- a/compiler/rustc_codegen_gcc/tests/run/volatile.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/volatile.rs
@@ -5,13 +5,14 @@
 
 use std::mem::MaybeUninit;
 
+#[allow(dead_code)]
 #[derive(Debug)]
 struct Struct {
     pointer: *const (),
     func: unsafe fn(*const ()),
 }
 
-fn func(ptr: *const ()) {
+fn func(_ptr: *const ()) {
 }
 
 fn main() {
diff --git a/compiler/rustc_codegen_gcc/tests/run/volatile2.rs b/compiler/rustc_codegen_gcc/tests/run/volatile2.rs
index a177b817ab3..bdcb8259878 100644
--- a/compiler/rustc_codegen_gcc/tests/run/volatile2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/volatile2.rs
@@ -6,8 +6,6 @@
 mod libc {
     #[link(name = "c")]
     extern "C" {
-        pub fn puts(s: *const u8) -> i32;
-
         pub fn sigaction(signum: i32, act: *const sigaction, oldact: *mut sigaction) -> i32;
         pub fn mmap(addr: *mut (), len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut ();
         pub fn mprotect(addr: *mut (), len: usize, prot: i32) -> i32;
@@ -61,7 +59,7 @@ fn main() {
             panic!("error: mmap failed");
         }
 
-        let p_count = (&mut COUNT) as *mut u32;
+        let p_count = (&raw mut COUNT) as *mut u32;
         p_count.write_volatile(0);
 
         // Trigger segfaults
@@ -94,7 +92,7 @@ fn main() {
 }
 
 unsafe extern "C" fn segv_handler(_: i32, _: *mut (), _: *mut ()) {
-    let p_count = (&mut COUNT) as *mut u32;
+    let p_count = (&raw mut COUNT) as *mut u32;
     p_count.write_volatile(p_count.read_volatile() + 1);
     let count = p_count.read_volatile();
 
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 3885f18271f..f197ea74473 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,5 +1,4 @@
 codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable
-codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fat-lto
 
 codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
 
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 1ea5a062254..c32f11b27f3 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -344,7 +344,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     llfn: &'ll Value,
     instance: ty::Instance<'tcx>,
 ) {
-    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
+    let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def);
 
     let mut to_add = SmallVec::<[_; 16]>::new();
 
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 74418adc43c..655e1c95373 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -7,7 +7,7 @@ use std::sync::Arc;
 use std::{io, iter, slice};
 
 use object::read::archive::ArchiveFile;
-use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
+use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
 use rustc_codegen_ssa::traits::*;
@@ -201,7 +201,7 @@ pub(crate) fn run_fat(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
-) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> {
+) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
     let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?;
@@ -217,7 +217,7 @@ pub(crate) fn run_thin(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     modules: Vec<(String, ThinBuffer)>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
-) -> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> {
+) -> Result<(Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> {
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
     let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?;
@@ -248,7 +248,7 @@ fn fat_lto(
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     symbols_below_threshold: &[*const libc::c_char],
-) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> {
+) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
     let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module");
     info!("going for a fat lto");
 
@@ -366,7 +366,7 @@ fn fat_lto(
         save_temp_bitcode(cgcx, &module, "lto.after-restriction");
     }
 
-    Ok(LtoModuleCodegen::Fat(module))
+    Ok(module)
 }
 
 pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>);
@@ -436,7 +436,7 @@ fn thin_lto(
     serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     symbols_below_threshold: &[*const libc::c_char],
-) -> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> {
+) -> Result<(Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> {
     let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis");
     unsafe {
         info!("going for that thin, thin LTO");
@@ -568,10 +568,7 @@ fn thin_lto(
             }
 
             info!(" - {}: re-compiled", module_name);
-            opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
-                shared: Arc::clone(&shared),
-                idx: module_index,
-            }));
+            opt_jobs.push(ThinModule { shared: Arc::clone(&shared), idx: module_index });
         }
 
         // Save the current ThinLTO import information for the next compilation
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index dfde4595590..8e82013e94a 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -39,6 +39,7 @@ impl OwnedTargetMachine {
         debug_info_compression: &CStr,
         use_emulated_tls: bool,
         args_cstr_buff: &[u8],
+        use_wasm_eh: bool,
     ) -> Result<Self, LlvmError<'static>> {
         assert!(args_cstr_buff.len() > 0);
         assert!(
@@ -72,6 +73,7 @@ impl OwnedTargetMachine {
                 use_emulated_tls,
                 args_cstr_buff.as_ptr() as *const c_char,
                 args_cstr_buff.len(),
+                use_wasm_eh,
             )
         };
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 313bf6d20a6..6f8fba2a30d 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -15,6 +15,7 @@ use rustc_codegen_ssa::back::write::{
     BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
     TargetMachineFactoryFn,
 };
+use rustc_codegen_ssa::base::wants_wasm_eh;
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind};
 use rustc_data_structures::profiling::SelfProfilerRef;
@@ -285,6 +286,8 @@ pub(crate) fn target_machine_factory(
     let file_name_display_preference =
         sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
 
+    let use_wasm_eh = wants_wasm_eh(sess);
+
     Arc::new(move |config: TargetMachineFactoryConfig| {
         let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
             let path = path.unwrap_or_default();
@@ -321,6 +324,7 @@ pub(crate) fn target_machine_factory(
             &debuginfo_compression,
             use_emulated_tls,
             &args_cstr_buff,
+            use_wasm_eh,
         )
     })
 }
@@ -817,10 +821,12 @@ pub(crate) fn link(
 
 pub(crate) fn codegen(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    dcx: DiagCtxtHandle<'_>,
     module: ModuleCodegen<ModuleLlvm>,
     config: &ModuleConfig,
 ) -> Result<CompiledModule, FatalError> {
+    let dcx = cgcx.create_dcx();
+    let dcx = dcx.handle();
+
     let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name);
     {
         let llmod = module.module_llvm.llmod();
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index dff68472847..829b3c513c2 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -2,7 +2,6 @@ use std::ptr;
 
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
 use rustc_codegen_ssa::ModuleCodegen;
-use rustc_codegen_ssa::back::write::ModuleConfig;
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
 use rustc_errors::FatalError;
@@ -461,7 +460,6 @@ pub(crate) fn differentiate<'ll>(
     module: &'ll ModuleCodegen<ModuleLlvm>,
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diff_items: Vec<AutoDiffItem>,
-    _config: &ModuleConfig,
 ) -> Result<(), FatalError> {
     for item in &diff_items {
         trace!("{}", item);
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 6d68eca60af..5a3dd90ab24 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -102,7 +102,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
         let is_hidden = if is_generic {
             // This is a monomorphization of a generic function.
             if !(cx.tcx.sess.opts.share_generics()
-                || tcx.codegen_fn_attrs(instance_def_id).inline
+                || tcx.codegen_instance_attrs(instance.def).inline
                     == rustc_attr_data_structures::InlineAttr::Never)
             {
                 // When not sharing generics, all instances are in the same
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 6a23becaa96..34bed2a1d2a 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -207,6 +207,11 @@ pub(crate) unsafe fn create_module<'ll>(
             // LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961
             target_data_layout = target_data_layout.replace("e-p6:32:32-i64", "e-i64");
         }
+        if sess.target.arch == "amdgpu" {
+            // LLVM 21 adds the address width for address space 8.
+            // See https://github.com/llvm/llvm-project/pull/139419
+            target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128")
+        }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index d50ad8a1a9c..31d49e86319 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -38,10 +38,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_llvm_autodiff_without_lto)]
-pub(crate) struct AutoDiffWithoutLTO;
-
-#[derive(Diagnostic)]
 #[diag(codegen_llvm_autodiff_without_enable)]
 pub(crate) struct AutoDiffWithoutEnable;
 
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 63ca51b006d..6db4e122ad6 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -26,11 +26,11 @@ use std::mem::ManuallyDrop;
 use back::owned_target_machine::OwnedTargetMachine;
 use back::write::{create_informational_target_machine, create_target_machine};
 use context::SimpleCx;
-use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
+use errors::ParseTargetMachineConfig;
 use llvm_util::target_config;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
-use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
+use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
 use rustc_codegen_ssa::back::write::{
     CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
 };
@@ -43,7 +43,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::Providers;
 use rustc_session::Session;
-use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest};
+use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
 use rustc_span::Symbol;
 
 mod back {
@@ -174,18 +174,29 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         back::write::link(cgcx, dcx, modules)
     }
-    fn run_fat_lto(
+    fn run_and_optimize_fat_lto(
         cgcx: &CodegenContext<Self>,
         modules: Vec<FatLtoInput<Self>>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
-    ) -> Result<LtoModuleCodegen<Self>, FatalError> {
-        back::lto::run_fat(cgcx, modules, cached_modules)
+        diff_fncs: Vec<AutoDiffItem>,
+    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        let mut module = back::lto::run_fat(cgcx, modules, cached_modules)?;
+
+        if !diff_fncs.is_empty() {
+            builder::autodiff::differentiate(&module, cgcx, diff_fncs)?;
+        }
+
+        let dcx = cgcx.create_dcx();
+        let dcx = dcx.handle();
+        back::lto::run_pass_manager(cgcx, dcx, &mut module, false)?;
+
+        Ok(module)
     }
     fn run_thin_lto(
         cgcx: &CodegenContext<Self>,
         modules: Vec<(String, Self::ThinBuffer)>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
-    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
+    ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError> {
         back::lto::run_thin(cgcx, modules, cached_modules)
     }
     fn optimize(
@@ -196,14 +207,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     ) -> Result<(), FatalError> {
         back::write::optimize(cgcx, dcx, module, config)
     }
-    fn optimize_fat(
-        cgcx: &CodegenContext<Self>,
-        module: &mut ModuleCodegen<Self::Module>,
-    ) -> Result<(), FatalError> {
-        let dcx = cgcx.create_dcx();
-        let dcx = dcx.handle();
-        back::lto::run_pass_manager(cgcx, dcx, module, false)
-    }
     fn optimize_thin(
         cgcx: &CodegenContext<Self>,
         thin: ThinModule<Self>,
@@ -212,11 +215,10 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     }
     fn codegen(
         cgcx: &CodegenContext<Self>,
-        dcx: DiagCtxtHandle<'_>,
         module: ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<CompiledModule, FatalError> {
-        back::write::codegen(cgcx, dcx, module, config)
+        back::write::codegen(cgcx, module, config)
     }
     fn prepare_thin(
         module: ModuleCodegen<Self::Module>,
@@ -227,19 +229,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
         (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
     }
-    /// Generate autodiff rules
-    fn autodiff(
-        cgcx: &CodegenContext<Self>,
-        module: &ModuleCodegen<Self::Module>,
-        diff_fncs: Vec<AutoDiffItem>,
-        config: &ModuleConfig,
-    ) -> Result<(), FatalError> {
-        if cgcx.lto != Lto::Fat {
-            let dcx = cgcx.create_dcx();
-            return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));
-        }
-        builder::autodiff::differentiate(module, cgcx, diff_fncs, config)
-    }
 }
 
 impl LlvmCodegenBackend {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 0b1e632cbc4..80a0e5c5acc 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2425,6 +2425,7 @@ unsafe extern "C" {
         UseEmulatedTls: bool,
         ArgsCstrBuff: *const c_char,
         ArgsCstrBuffLen: usize,
+        UseWasmEH: bool,
     ) -> *mut TargetMachine;
 
     pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 8f70270f203..f9edaded60d 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -55,8 +55,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
         llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
-        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-        base::set_link_section(lldecl, attrs);
+        let attrs = self.tcx.codegen_instance_attrs(instance.def);
+        base::set_link_section(lldecl, &attrs);
         if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
             && self.tcx.sess.target.supports_comdat()
         {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index b46773396fc..5ce301c0eb9 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2542,12 +2542,7 @@ fn add_order_independent_options(
         // sections to ensure we have all the data for PGO.
         let keep_metadata =
             crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled();
-        if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols
-        {
-            cmd.gc_sections(keep_metadata);
-        } else {
-            cmd.no_gc_sections();
-        }
+        cmd.gc_sections(keep_metadata);
     }
 
     cmd.set_output_kind(link_output_kind, crate_type, out_filename);
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e0a3ad55be0..050797354b4 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -326,7 +326,6 @@ pub(crate) trait Linker {
         link_or_cc_args(self, &[path]);
     }
     fn gc_sections(&mut self, keep_metadata: bool);
-    fn no_gc_sections(&mut self);
     fn full_relro(&mut self);
     fn partial_relro(&mut self);
     fn no_relro(&mut self);
@@ -688,12 +687,6 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn no_gc_sections(&mut self) {
-        if self.is_gnu || self.sess.target.is_like_wasm {
-            self.link_arg("--no-gc-sections");
-        }
-    }
-
     fn optimize(&mut self) {
         if !self.is_gnu && !self.sess.target.is_like_wasm {
             return;
@@ -1010,10 +1003,6 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn no_gc_sections(&mut self) {
-        self.link_arg("/OPT:NOREF,NOICF");
-    }
-
     fn full_relro(&mut self) {
         // noop
     }
@@ -1243,10 +1232,6 @@ impl<'a> Linker for EmLinker<'a> {
         // noop
     }
 
-    fn no_gc_sections(&mut self) {
-        // noop
-    }
-
     fn optimize(&mut self) {
         // Emscripten performs own optimizations
         self.cc_arg(match self.sess.opts.optimize {
@@ -1418,10 +1403,6 @@ impl<'a> Linker for WasmLd<'a> {
         self.link_arg("--gc-sections");
     }
 
-    fn no_gc_sections(&mut self) {
-        self.link_arg("--no-gc-sections");
-    }
-
     fn optimize(&mut self) {
         // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and
         // only differentiates -O0 and -O1. It does not apply to LTO.
@@ -1567,10 +1548,6 @@ impl<'a> Linker for L4Bender<'a> {
         }
     }
 
-    fn no_gc_sections(&mut self) {
-        self.link_arg("--no-gc-sections");
-    }
-
     fn optimize(&mut self) {
         // GNU-style linkers support optimization with -O. GNU ld doesn't
         // need a numeric argument, but other linkers do.
@@ -1734,10 +1711,6 @@ impl<'a> Linker for AixLinker<'a> {
         self.link_arg("-bgc");
     }
 
-    fn no_gc_sections(&mut self) {
-        self.link_arg("-bnogc");
-    }
-
     fn optimize(&mut self) {}
 
     fn pgo_gen(&mut self) {
@@ -1982,8 +1955,6 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
-    fn no_gc_sections(&mut self) {}
-
     fn pgo_gen(&mut self) {}
 
     fn no_crt_objects(&mut self) {}
@@ -2057,8 +2028,6 @@ impl<'a> Linker for LlbcLinker<'a> {
 
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
-    fn no_gc_sections(&mut self) {}
-
     fn pgo_gen(&mut self) {}
 
     fn no_crt_objects(&mut self) {}
@@ -2139,8 +2108,6 @@ impl<'a> Linker for BpfLinker<'a> {
 
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
-    fn no_gc_sections(&mut self) {}
-
     fn pgo_gen(&mut self) {}
 
     fn no_crt_objects(&mut self) {}
diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs
index ce6fe8a191b..b49b6783bbd 100644
--- a/compiler/rustc_codegen_ssa/src/back/lto.rs
+++ b/compiler/rustc_codegen_ssa/src/back/lto.rs
@@ -1,13 +1,8 @@
 use std::ffi::CString;
 use std::sync::Arc;
 
-use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_data_structures::memmap::Mmap;
-use rustc_errors::FatalError;
 
-use super::write::CodegenContext;
-use crate::ModuleCodegen;
-use crate::back::write::ModuleConfig;
 use crate::traits::*;
 
 pub struct ThinModule<B: WriteBackendMethods> {
@@ -42,61 +37,6 @@ pub struct ThinShared<B: WriteBackendMethods> {
     pub module_names: Vec<CString>,
 }
 
-pub enum LtoModuleCodegen<B: WriteBackendMethods> {
-    Fat(ModuleCodegen<B::Module>),
-    Thin(ThinModule<B>),
-}
-
-impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
-    pub fn name(&self) -> &str {
-        match *self {
-            LtoModuleCodegen::Fat(_) => "everything",
-            LtoModuleCodegen::Thin(ref m) => m.name(),
-        }
-    }
-
-    /// Optimize this module within the given codegen context.
-    pub fn optimize(
-        self,
-        cgcx: &CodegenContext<B>,
-    ) -> Result<ModuleCodegen<B::Module>, FatalError> {
-        match self {
-            LtoModuleCodegen::Fat(mut module) => {
-                B::optimize_fat(cgcx, &mut module)?;
-                Ok(module)
-            }
-            LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin),
-        }
-    }
-
-    /// A "gauge" of how costly it is to optimize this module, used to sort
-    /// biggest modules first.
-    pub fn cost(&self) -> u64 {
-        match *self {
-            // Only one module with fat LTO, so the cost doesn't matter.
-            LtoModuleCodegen::Fat(_) => 0,
-            LtoModuleCodegen::Thin(ref m) => m.cost(),
-        }
-    }
-
-    /// Run autodiff on Fat LTO module
-    pub fn autodiff(
-        self,
-        cgcx: &CodegenContext<B>,
-        diff_fncs: Vec<AutoDiffItem>,
-        config: &ModuleConfig,
-    ) -> Result<LtoModuleCodegen<B>, FatalError> {
-        match &self {
-            LtoModuleCodegen::Fat(module) => {
-                B::autodiff(cgcx, &module, diff_fncs, config)?;
-            }
-            _ => panic!("autodiff called with non-fat LTO module"),
-        }
-
-        Ok(self)
-    }
-}
-
 pub enum SerializedModule<M: ModuleBufferMethods> {
     Local(M),
     FromRlib(Vec<u8>),
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index d2a64ec2993..50a7cba300b 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -397,50 +397,31 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
     }
 }
 
-fn generate_lto_work<B: ExtraBackendMethods>(
+fn generate_thin_lto_work<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
-    autodiff: Vec<AutoDiffItem>,
-    needs_fat_lto: Vec<FatLtoInput<B>>,
     needs_thin_lto: Vec<(String, B::ThinBuffer)>,
     import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
 ) -> Vec<(WorkItem<B>, u64)> {
-    let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work");
-
-    if !needs_fat_lto.is_empty() {
-        assert!(needs_thin_lto.is_empty());
-        let mut module =
-            B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise());
-        if cgcx.lto == Lto::Fat && !autodiff.is_empty() {
-            let config = cgcx.config(ModuleKind::Regular);
-            module = module.autodiff(cgcx, autodiff, config).unwrap_or_else(|e| e.raise());
-        }
-        // We are adding a single work item, so the cost doesn't matter.
-        vec![(WorkItem::LTO(module), 0)]
-    } else {
-        if !autodiff.is_empty() {
-            let dcx = cgcx.create_dcx();
-            dcx.handle().emit_fatal(AutodiffWithoutLto {});
-        }
-        assert!(needs_fat_lto.is_empty());
-        let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules)
-            .unwrap_or_else(|e| e.raise());
-        lto_modules
-            .into_iter()
-            .map(|module| {
-                let cost = module.cost();
-                (WorkItem::LTO(module), cost)
-            })
-            .chain(copy_jobs.into_iter().map(|wp| {
-                (
-                    WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
-                        name: wp.cgu_name.clone(),
-                        source: wp,
-                    }),
-                    0, // copying is very cheap
-                )
-            }))
-            .collect()
-    }
+    let _prof_timer = cgcx.prof.generic_activity("codegen_thin_generate_lto_work");
+
+    let (lto_modules, copy_jobs) =
+        B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules).unwrap_or_else(|e| e.raise());
+    lto_modules
+        .into_iter()
+        .map(|module| {
+            let cost = module.cost();
+            (WorkItem::ThinLto(module), cost)
+        })
+        .chain(copy_jobs.into_iter().map(|wp| {
+            (
+                WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
+                    name: wp.cgu_name.clone(),
+                    source: wp,
+                }),
+                0, // copying is very cheap
+            )
+        }))
+        .collect()
 }
 
 struct CompiledModules {
@@ -470,6 +451,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'_>,
     target_cpu: String,
+    autodiff_items: &[AutoDiffItem],
 ) -> OngoingCodegen<B> {
     let (coordinator_send, coordinator_receive) = channel();
 
@@ -488,6 +470,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
         backend.clone(),
         tcx,
         &crate_info,
+        autodiff_items,
         shared_emitter,
         codegen_worker_send,
         coordinator_receive,
@@ -736,15 +719,23 @@ pub(crate) enum WorkItem<B: WriteBackendMethods> {
     /// Copy the post-LTO artifacts from the incremental cache to the output
     /// directory.
     CopyPostLtoArtifacts(CachedModuleCodegen),
-    /// Performs (Thin)LTO on the given module.
-    LTO(lto::LtoModuleCodegen<B>),
+    /// Performs fat LTO on the given module.
+    FatLto {
+        needs_fat_lto: Vec<FatLtoInput<B>>,
+        import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
+        autodiff: Vec<AutoDiffItem>,
+    },
+    /// Performs thin-LTO on the given module.
+    ThinLto(lto::ThinModule<B>),
 }
 
 impl<B: WriteBackendMethods> WorkItem<B> {
     fn module_kind(&self) -> ModuleKind {
         match *self {
             WorkItem::Optimize(ref m) => m.kind,
-            WorkItem::CopyPostLtoArtifacts(_) | WorkItem::LTO(_) => ModuleKind::Regular,
+            WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto { .. } | WorkItem::ThinLto(_) => {
+                ModuleKind::Regular
+            }
         }
     }
 
@@ -792,7 +783,8 @@ impl<B: WriteBackendMethods> WorkItem<B> {
         match self {
             WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name),
             WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name),
-            WorkItem::LTO(m) => desc("lto", "LTO module", m.name()),
+            WorkItem::FatLto { .. } => desc("lto", "fat LTO module", "everything"),
+            WorkItem::ThinLto(m) => desc("lto", "thin-LTO module", m.name()),
         }
     }
 }
@@ -996,12 +988,24 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
     })
 }
 
-fn execute_lto_work_item<B: ExtraBackendMethods>(
+fn execute_fat_lto_work_item<B: ExtraBackendMethods>(
+    cgcx: &CodegenContext<B>,
+    needs_fat_lto: Vec<FatLtoInput<B>>,
+    import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
+    autodiff: Vec<AutoDiffItem>,
+    module_config: &ModuleConfig,
+) -> Result<WorkItemResult<B>, FatalError> {
+    let module = B::run_and_optimize_fat_lto(cgcx, needs_fat_lto, import_only_modules, autodiff)?;
+    let module = B::codegen(cgcx, module, module_config)?;
+    Ok(WorkItemResult::Finished(module))
+}
+
+fn execute_thin_lto_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
-    module: lto::LtoModuleCodegen<B>,
+    module: lto::ThinModule<B>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
-    let module = module.optimize(cgcx)?;
+    let module = B::optimize_thin(cgcx, module)?;
     finish_intra_module_work(cgcx, module, module_config)
 }
 
@@ -1010,11 +1014,8 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
     module: ModuleCodegen<B::Module>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
-    let dcx = cgcx.create_dcx();
-    let dcx = dcx.handle();
-
     if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator {
-        let module = B::codegen(cgcx, dcx, module, module_config)?;
+        let module = B::codegen(cgcx, module, module_config)?;
         Ok(WorkItemResult::Finished(module))
     } else {
         Ok(WorkItemResult::NeedsLink(module))
@@ -1031,9 +1032,6 @@ pub(crate) enum Message<B: WriteBackendMethods> {
     /// Sent from a backend worker thread.
     WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize },
 
-    /// A vector containing all the AutoDiff tasks that we have to pass to Enzyme.
-    AddAutoDiffItems(Vec<AutoDiffItem>),
-
     /// The frontend has finished generating something (backend IR or a
     /// post-LTO artifact) for a codegen unit, and it should be passed to the
     /// backend. Sent from the main thread.
@@ -1100,6 +1098,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'_>,
     crate_info: &CrateInfo,
+    autodiff_items: &[AutoDiffItem],
     shared_emitter: SharedEmitter,
     codegen_worker_send: Sender<CguMessage>,
     coordinator_receive: Receiver<Box<dyn Any + Send>>,
@@ -1109,6 +1108,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
 ) -> thread::JoinHandle<Result<CompiledModules, ()>> {
     let coordinator_send = tx_to_llvm_workers;
     let sess = tcx.sess;
+    let autodiff_items = autodiff_items.to_vec();
 
     let mut each_linked_rlib_for_lto = Vec::new();
     drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| {
@@ -1362,7 +1362,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
 
         // This is where we collect codegen units that have gone all the way
         // through codegen and LLVM.
-        let mut autodiff_items = Vec::new();
         let mut compiled_modules = vec![];
         let mut compiled_allocator_module = None;
         let mut needs_link = Vec::new();
@@ -1474,20 +1473,37 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     let needs_thin_lto = mem::take(&mut needs_thin_lto);
                     let import_only_modules = mem::take(&mut lto_import_only_modules);
 
-                    for (work, cost) in generate_lto_work(
-                        &cgcx,
-                        autodiff_items.clone(),
-                        needs_fat_lto,
-                        needs_thin_lto,
-                        import_only_modules,
-                    ) {
-                        let insertion_index = work_items
-                            .binary_search_by_key(&cost, |&(_, cost)| cost)
-                            .unwrap_or_else(|e| e);
-                        work_items.insert(insertion_index, (work, cost));
+                    if !needs_fat_lto.is_empty() {
+                        assert!(needs_thin_lto.is_empty());
+
+                        work_items.push((
+                            WorkItem::FatLto {
+                                needs_fat_lto,
+                                import_only_modules,
+                                autodiff: autodiff_items.clone(),
+                            },
+                            0,
+                        ));
                         if cgcx.parallel {
                             helper.request_token();
                         }
+                    } else {
+                        if !autodiff_items.is_empty() {
+                            let dcx = cgcx.create_dcx();
+                            dcx.handle().emit_fatal(AutodiffWithoutLto {});
+                        }
+
+                        for (work, cost) in
+                            generate_thin_lto_work(&cgcx, needs_thin_lto, import_only_modules)
+                        {
+                            let insertion_index = work_items
+                                .binary_search_by_key(&cost, |&(_, cost)| cost)
+                                .unwrap_or_else(|e| e);
+                            work_items.insert(insertion_index, (work, cost));
+                            if cgcx.parallel {
+                                helper.request_token();
+                            }
+                        }
                     }
                 }
 
@@ -1616,10 +1632,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     main_thread_state = MainThreadState::Idle;
                 }
 
-                Message::AddAutoDiffItems(mut items) => {
-                    autodiff_items.append(&mut items);
-                }
-
                 Message::CodegenComplete => {
                     if codegen_state != Aborted {
                         codegen_state = Completed;
@@ -1702,7 +1714,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
             let dcx = dcx.handle();
             let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?;
             let module =
-                B::codegen(&cgcx, dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?;
+                B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?;
             compiled_modules.push(module);
         }
 
@@ -1842,10 +1854,22 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
                     );
                     Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config))
                 }
-                WorkItem::LTO(m) => {
+                WorkItem::FatLto { needs_fat_lto, import_only_modules, autodiff } => {
+                    let _timer = cgcx
+                        .prof
+                        .generic_activity_with_arg("codegen_module_perform_lto", "everything");
+                    execute_fat_lto_work_item(
+                        &cgcx,
+                        needs_fat_lto,
+                        import_only_modules,
+                        autodiff,
+                        module_config,
+                    )
+                }
+                WorkItem::ThinLto(m) => {
                     let _timer =
                         cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name());
-                    execute_lto_work_item(&cgcx, m, module_config)
+                    execute_thin_lto_work_item(&cgcx, m, module_config)
                 }
             })
         };
@@ -2082,10 +2106,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
         drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
     }
 
-    pub(crate) fn submit_autodiff_items(&self, items: Vec<AutoDiffItem>) {
-        drop(self.coordinator.sender.send(Box::new(Message::<B>::AddAutoDiffItems(items))));
-    }
-
     pub(crate) fn check_for_errors(&self, sess: &Session) {
         self.shared_emitter_main.check(sess, false);
     }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 18581f854b6..833456abb8a 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -647,7 +647,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 ) -> OngoingCodegen<B> {
     // Skip crate items and just output metadata in -Z no-codegen mode.
     if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
-        let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu);
+        let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, &[]);
 
         ongoing_codegen.codegen_finished(tcx);
 
@@ -667,7 +667,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     // codegen units.
     let MonoItemPartitions { codegen_units, autodiff_items, .. } =
         tcx.collect_and_partition_mono_items(());
-    let autodiff_fncs = autodiff_items.to_vec();
 
     // Force all codegen_unit queries so they are already either red or green
     // when compile_codegen_unit accesses them. We are not able to re-execute
@@ -680,7 +679,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         }
     }
 
-    let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu);
+    let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, autodiff_items);
 
     // Codegen an allocator shim, if necessary.
     if let Some(kind) = allocator_kind_for_codegen(tcx) {
@@ -710,10 +709,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         );
     }
 
-    if !autodiff_fncs.is_empty() {
-        ongoing_codegen.submit_autodiff_items(autodiff_fncs);
-    }
-
     // For better throughput during parallel processing by LLVM, we used to sort
     // CGUs largest to smallest. This would lead to better thread utilization
     // by, for example, preventing a large CGU from being processed last and
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 025f5fb54f4..b8f635ab781 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -356,7 +356,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             LocalRef::Operand(operand) => {
                 // Don't spill operands onto the stack in naked functions.
                 // See: https://github.com/rust-lang/rust/issues/42779
-                let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
+                let attrs = bx.tcx().codegen_instance_attrs(self.instance.def);
                 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
                     return;
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index fa69820d5d2..50d0f910744 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -390,9 +390,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let mut num_untupled = None;
 
-    let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id());
-    let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED);
-    if naked {
+    let codegen_fn_attrs = bx.tcx().codegen_instance_attrs(fx.instance.def);
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
         return vec![];
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index beaf8950978..42e435cf0a3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -128,7 +128,7 @@ fn prefix_and_suffix<'tcx>(
     let is_arm = tcx.sess.target.arch == "arm";
     let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode);
 
-    let attrs = tcx.codegen_fn_attrs(instance.def_id());
+    let attrs = tcx.codegen_instance_attrs(instance.def);
     let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
 
     // If no alignment is specified, an alignment of 4 bytes is used.
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_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index e90463aacc8..e872f8434e5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -611,18 +611,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
                     let fn_ty = bx.fn_decl_backend_type(fn_abi);
                     let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() {
-                        Some(bx.tcx().codegen_fn_attrs(instance.def_id()))
+                        Some(bx.tcx().codegen_instance_attrs(instance.def))
                     } else {
                         None
                     };
-                    bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance))
+                    bx.call(
+                        fn_ty,
+                        fn_attrs.as_deref(),
+                        Some(fn_abi),
+                        fn_ptr,
+                        &[],
+                        None,
+                        Some(instance),
+                    )
                 } else {
                     bx.get_static(def_id)
                 };
                 OperandRef { val: OperandValue::Immediate(static_), layout }
             }
             mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
-            mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"),
+            mir::Rvalue::Repeat(ref elem, len_const) => {
+                // All arrays have `BackendRepr::Memory`, so only the ZST cases
+                // end up here. Anything else forces the destination local to be
+                // `Memory`, and thus ends up handled in `codegen_rvalue` instead.
+                let operand = self.codegen_operand(bx, elem);
+                let array_ty = Ty::new_array_with_const_len(bx.tcx(), operand.layout.ty, len_const);
+                let array_ty = self.monomorphize(array_ty);
+                let array_layout = bx.layout_of(array_ty);
+                assert!(array_layout.is_zst());
+                OperandRef { val: OperandValue::ZeroSized, layout: array_layout }
+            }
             mir::Rvalue::Aggregate(ref kind, ref fields) => {
                 let (variant_index, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
@@ -992,12 +1010,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::NullaryOp(..) |
             mir::Rvalue::ThreadLocalRef(_) |
             mir::Rvalue::Use(..) |
+            mir::Rvalue::Repeat(..) | // (*)
             mir::Rvalue::Aggregate(..) | // (*)
             mir::Rvalue::WrapUnsafeBinder(..) => // (*)
                 true,
-            // Arrays are always aggregates, so it's not worth checking anything here.
-            // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
-            mir::Rvalue::Repeat(..) => false,
         }
 
         // (*) this is only true if the type is suitable
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 7b4268abe4b..b9040c330fb 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -41,12 +41,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
                 base::codegen_global_asm(cx, item_id);
             }
             MonoItem::Fn(instance) => {
-                if cx
-                    .tcx()
-                    .codegen_fn_attrs(instance.def_id())
-                    .flags
-                    .contains(CodegenFnAttrFlags::NAKED)
-                {
+                let flags = cx.tcx().codegen_instance_attrs(instance.def).flags;
+                if flags.contains(CodegenFnAttrFlags::NAKED) {
                     naked_asm::codegen_naked_asm::<Bx::CodegenCx>(cx, instance, item_data);
                 } else {
                     base::codegen_instance::<Bx>(cx, instance);
@@ -75,7 +71,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
                 cx.predefine_static(def_id, linkage, visibility, symbol_name);
             }
             MonoItem::Fn(instance) => {
-                let attrs = cx.tcx().codegen_fn_attrs(instance.def_id());
+                let attrs = cx.tcx().codegen_instance_attrs(instance.def);
 
                 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
                     // do not define this function; it will become a global assembly block
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 53df99993f0..def4ec13e87 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -149,14 +149,14 @@ fn parse_rust_feature_flag<'a>(
         if let Some(base_feature) = feature.strip_prefix('+') {
             // Skip features that are not target features, but rustc features.
             if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
-                return;
+                continue;
             }
 
             callback(base_feature, sess.target.implied_target_features(base_feature), true)
         } else if let Some(base_feature) = feature.strip_prefix('-') {
             // Skip features that are not target features, but rustc features.
             if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
-                return;
+                continue;
             }
 
             // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index 07a0609fda1..5e993640472 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -2,7 +2,7 @@ use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_errors::{DiagCtxtHandle, FatalError};
 use rustc_middle::dep_graph::WorkProduct;
 
-use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
+use crate::back::lto::{SerializedModule, ThinModule};
 use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
 use crate::{CompiledModule, ModuleCodegen};
 
@@ -20,13 +20,14 @@ pub trait WriteBackendMethods: Clone + 'static {
         dcx: DiagCtxtHandle<'_>,
         modules: Vec<ModuleCodegen<Self::Module>>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
-    /// Performs fat LTO by merging all modules into a single one and returning it
-    /// for further optimization.
-    fn run_fat_lto(
+    /// Performs fat LTO by merging all modules into a single one, running autodiff
+    /// if necessary and running any further optimizations
+    fn run_and_optimize_fat_lto(
         cgcx: &CodegenContext<Self>,
         modules: Vec<FatLtoInput<Self>>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
-    ) -> Result<LtoModuleCodegen<Self>, FatalError>;
+        diff_fncs: Vec<AutoDiffItem>,
+    ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     /// Performs thin LTO by performing necessary global analysis and returning two
     /// lists, one of the modules that need optimization and another for modules that
     /// can simply be copied over from the incr. comp. cache.
@@ -34,7 +35,7 @@ pub trait WriteBackendMethods: Clone + 'static {
         cgcx: &CodegenContext<Self>,
         modules: Vec<(String, Self::ThinBuffer)>,
         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
-    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError>;
+    ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError>;
     fn print_pass_timings(&self);
     fn print_statistics(&self);
     fn optimize(
@@ -43,17 +44,12 @@ pub trait WriteBackendMethods: Clone + 'static {
         module: &mut ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<(), FatalError>;
-    fn optimize_fat(
-        cgcx: &CodegenContext<Self>,
-        llmod: &mut ModuleCodegen<Self::Module>,
-    ) -> Result<(), FatalError>;
     fn optimize_thin(
         cgcx: &CodegenContext<Self>,
         thin: ThinModule<Self>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     fn codegen(
         cgcx: &CodegenContext<Self>,
-        dcx: DiagCtxtHandle<'_>,
         module: ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<CompiledModule, FatalError>;
@@ -62,12 +58,6 @@ pub trait WriteBackendMethods: Clone + 'static {
         want_summary: bool,
     ) -> (String, Self::ThinBuffer);
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
-    fn autodiff(
-        cgcx: &CodegenContext<Self>,
-        module: &ModuleCodegen<Self::Module>,
-        diff_fncs: Vec<AutoDiffItem>,
-        config: &ModuleConfig,
-    ) -> Result<(), FatalError>;
 }
 
 pub trait ThinBufferMethods: Send + Sync {
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index c9b7356432d..aa0bc42d448 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -56,6 +56,17 @@ const_eval_const_context = {$kind ->
     *[other] {""}
 }
 
+const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global
+    .note = use `const_make_global` to make allocated pointers immutable before returning
+
+const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc}
+
+const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}
+
+const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr}
+
+const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object
+
 const_eval_copy_nonoverlapping_overlapping =
     `copy_nonoverlapping` called on overlapping ranges
 
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 9ab8e0692e1..ebf18c6f2ac 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -93,7 +93,7 @@ pub fn rustc_allow_const_fn_unstable(
 /// world into two functions: those that are safe to expose on stable (and hence may not use
 /// unstable features, not even recursively), and those that are not.
 pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    // A default body in a `#[const_trait]` is const-stable when the trait is const-stable.
+    // A default body in a `const trait` is const-stable when the trait is const-stable.
     if tcx.is_const_default_method(def_id) {
         return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id));
     }
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index b6e2682af36..438aed41b8b 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -49,7 +49,6 @@ impl HasStaticRootDefId for DummyMachine {
 
 impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
     interpret::compile_time_machine!(<'tcx>);
-    type MemoryKind = !;
     const PANIC_ON_ALLOC_FAIL: bool = true;
 
     // We want to just eval random consts in the program, so `eval_mir_const` can fail.
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 08fc03d9c46..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::{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::{
-    ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, 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.
@@ -22,8 +22,22 @@ pub enum ConstEvalErrKind {
     ModifiedGlobal,
     RecursiveStatic,
     AssertFailure(AssertKind<ConstInt>),
-    Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
+    Panic {
+        msg: Symbol,
+        line: u32,
+        col: u32,
+        file: Symbol,
+    },
     WriteThroughImmutablePointer,
+    /// Called `const_make_global` twice.
+    ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId),
+    /// Called `const_make_global` on a non-heap pointer.
+    ConstMakeGlobalPtrIsNonHeap(Pointer<Option<CtfeProvenance>>),
+    /// Called `const_make_global` on a dangling pointer.
+    ConstMakeGlobalWithDanglingPtr(Pointer<Option<CtfeProvenance>>),
+    /// Called `const_make_global` on a pointer that does not start at the
+    /// beginning of an object.
+    ConstMakeGlobalWithOffset(Pointer<Option<CtfeProvenance>>),
 }
 
 impl MachineStopType for ConstEvalErrKind {
@@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind {
             RecursiveStatic => const_eval_recursive_static,
             AssertFailure(x) => x.diagnostic_message(),
             WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer,
+            ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
+                const_eval_const_make_global_ptr_already_made_global
+            }
+            ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap,
+            ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr,
+            ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset,
         }
     }
     fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
@@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind {
             Panic { msg, .. } => {
                 adder("msg".into(), msg.into_diag_arg(&mut None));
             }
+            ConstMakeGlobalPtrIsNonHeap(ptr)
+            | ConstMakeGlobalWithOffset(ptr)
+            | ConstMakeGlobalWithDanglingPtr(ptr) => {
+                adder("ptr".into(), format!("{ptr:?}").into_diag_arg(&mut None));
+            }
+            ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => {
+                adder("alloc".into(), alloc.into_diag_arg(&mut None));
+            }
         }
     }
 }
@@ -135,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,
@@ -145,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
@@ -170,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 4bd4b493009..f584f6c948e 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -18,7 +18,7 @@ use tracing::{debug, instrument, trace};
 use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine};
 use crate::const_eval::CheckAlignment;
 use crate::interpret::{
-    CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind,
+    CtfeValidationMode, GlobalId, Immediate, InternError, InternKind, InterpCx, InterpErrorKind,
     InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ReturnContinuation, create_static_alloc,
     intern_const_alloc_recursive, interp_ok, throw_exhaust,
 };
@@ -93,25 +93,30 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
     // Since evaluation had no errors, validate the resulting constant.
     const_validate_mplace(ecx, &ret, cid)?;
 
-    // Only report this after validation, as validaiton produces much better diagnostics.
+    // Only report this after validation, as validation produces much better diagnostics.
     // FIXME: ensure validation always reports this and stop making interning care about it.
 
     match intern_result {
         Ok(()) => {}
-        Err(InternResult::FoundDanglingPointer) => {
+        Err(InternError::DanglingPointer) => {
             throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
                 ecx.tcx
                     .dcx()
                     .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }),
             )));
         }
-        Err(InternResult::FoundBadMutablePointer) => {
+        Err(InternError::BadMutablePointer) => {
             throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
                 ecx.tcx
                     .dcx()
                     .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }),
             )));
         }
+        Err(InternError::ConstAllocNotGlobal) => {
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
+                ecx.tcx.dcx().emit_err(errors::ConstHeapPtrInFinal { span: ecx.tcx.span }),
+            )));
+        }
     }
 
     interp_ok(R::make_result(ret, ecx))
@@ -406,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()),
@@ -446,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/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 52fc898192a..f24fb18f83b 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -169,13 +169,19 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum MemoryKind {
-    Heap,
+    Heap {
+        /// Indicates whether `make_global` was called on this allocation.
+        /// If this is `true`, the allocation must be immutable.
+        was_made_global: bool,
+    },
 }
 
 impl fmt::Display for MemoryKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            MemoryKind::Heap => write!(f, "heap allocation"),
+            MemoryKind::Heap { was_made_global } => {
+                write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" })
+            }
         }
     }
 }
@@ -184,7 +190,7 @@ impl interpret::MayLeak for MemoryKind {
     #[inline(always)]
     fn may_leak(self) -> bool {
         match self {
-            MemoryKind::Heap => false,
+            MemoryKind::Heap { was_made_global } => was_made_global,
         }
     }
 }
@@ -314,8 +320,6 @@ impl<'tcx> CompileTimeMachine<'tcx> {
 impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
     compile_time_machine!(<'tcx>);
 
-    type MemoryKind = MemoryKind;
-
     const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
 
     #[inline(always)]
@@ -359,8 +363,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         if let ty::InstanceKind::Item(def) = instance.def {
             // Execution might have wandered off into other crates, so we cannot do a stability-
             // sensitive check here. But we can at least rule out functions that are not const at
-            // all. That said, we have to allow calling functions inside a trait marked with
-            // #[const_trait]. These *are* const-checked!
+            // all. That said, we have to allow calling functions inside a `const trait`. These
+            // *are* const-checked!
             if !ecx.tcx.is_const_fn(def) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) {
                 // We certainly do *not* want to actually call the fn
                 // though, so be sure we return here.
@@ -420,7 +424,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                 let ptr = ecx.allocate_ptr(
                     Size::from_bytes(size),
                     align,
-                    interpret::MemoryKind::Machine(MemoryKind::Heap),
+                    interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
                     AllocInit::Uninit,
                 )?;
                 ecx.write_pointer(ptr, dest)?;
@@ -453,10 +457,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                     ecx.deallocate_ptr(
                         ptr,
                         Some((size, align)),
-                        interpret::MemoryKind::Machine(MemoryKind::Heap),
+                        interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
                     )?;
                 }
             }
+
+            sym::const_make_global => {
+                let ptr = ecx.read_pointer(&args[0])?;
+                ecx.make_const_heap_ptr_global(ptr)?;
+                ecx.write_pointer(ptr, dest)?;
+            }
+
             // The intrinsic represents whether the value is known to the optimizer (LLVM).
             // We're not doing any optimizations here, so there is no optimizer that could know the value.
             // (We know the value here in the machine of course, but this is the runtime of that code,
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 49cd7138748..b6a64035261 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -44,6 +44,14 @@ pub(crate) struct MutablePtrInFinal {
 }
 
 #[derive(Diagnostic)]
+#[diag(const_eval_const_heap_ptr_in_final)]
+#[note]
+pub(crate) struct ConstHeapPtrInFinal {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(const_eval_unstable_in_stable_exposed)]
 pub(crate) struct UnstableInStableExposed {
     pub gate: String,
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/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index f0f958d069e..bb59b9f5418 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -26,21 +26,18 @@ use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::def_id::LocalDefId;
 use tracing::{instrument, trace};
 
-use super::{
-    AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok,
-};
-use crate::const_eval;
+use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, interp_ok};
 use crate::const_eval::DummyMachine;
-use crate::errors::NestedStaticInThreadLocal;
+use crate::{const_eval, errors};
 
-pub trait CompileTimeMachine<'tcx, T> = Machine<
+pub trait CompileTimeMachine<'tcx> = Machine<
         'tcx,
-        MemoryKind = T,
+        MemoryKind = const_eval::MemoryKind,
         Provenance = CtfeProvenance,
         ExtraFnVal = !,
         FrameExtra = (),
         AllocExtra = (),
-        MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>,
+        MemoryMap = FxIndexMap<AllocId, (MemoryKind<const_eval::MemoryKind>, Allocation)>,
     > + HasStaticRootDefId;
 
 pub trait HasStaticRootDefId {
@@ -62,18 +59,32 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
 /// already mutable (as a sanity check).
 ///
 /// Returns an iterator over all relocations referred to by this allocation.
-fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
+fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>(
     ecx: &mut InterpCx<'tcx, M>,
     alloc_id: AllocId,
     mutability: Mutability,
     disambiguator: Option<&mut DisambiguatorState>,
-) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, ()> {
+) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, InternError> {
     trace!("intern_shallow {:?}", alloc_id);
     // remove allocation
     // FIXME(#120456) - is `swap_remove` correct?
-    let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
-        return Err(());
+    let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
+        return Err(InternError::DanglingPointer);
     };
+
+    match kind {
+        MemoryKind::Machine(const_eval::MemoryKind::Heap { was_made_global }) => {
+            if !was_made_global {
+                // Attempting to intern a `const_allocate`d pointer that was not made global via
+                // `const_make_global`. We want to error here, but we have to first put the
+                // allocation back into the `alloc_map` to keep things in a consistent state.
+                ecx.memory.alloc_map.insert(alloc_id, (kind, alloc));
+                return Err(InternError::ConstAllocNotGlobal);
+            }
+        }
+        MemoryKind::Stack | MemoryKind::CallerLocation => {}
+    }
+
     // Set allocation mutability as appropriate. This is used by LLVM to put things into
     // read-only memory, and also by Miri when evaluating other globals that
     // access this one.
@@ -99,7 +110,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
     } else {
         ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
     }
-    Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
+    Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov))
 }
 
 /// Creates a new `DefId` and feeds all the right queries to make this `DefId`
@@ -125,7 +136,7 @@ fn intern_as_new_static<'tcx>(
     tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
 
     if tcx.is_thread_local_static(static_id.into()) {
-        tcx.dcx().emit_err(NestedStaticInThreadLocal { span: tcx.def_span(static_id) });
+        tcx.dcx().emit_err(errors::NestedStaticInThreadLocal { span: tcx.def_span(static_id) });
     }
 
     // These do not inherit the codegen attrs of the parent static allocation, since
@@ -151,9 +162,10 @@ pub enum InternKind {
 }
 
 #[derive(Debug)]
-pub enum InternResult {
-    FoundBadMutablePointer,
-    FoundDanglingPointer,
+pub enum InternError {
+    BadMutablePointer,
+    DanglingPointer,
+    ConstAllocNotGlobal,
 }
 
 /// Intern `ret` and everything it references.
@@ -163,11 +175,11 @@ pub enum InternResult {
 ///
 /// For `InternKind::Static` the root allocation will not be interned, but must be handled by the caller.
 #[instrument(level = "debug", skip(ecx))]
-pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval::MemoryKind>>(
+pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>(
     ecx: &mut InterpCx<'tcx, M>,
     intern_kind: InternKind,
     ret: &MPlaceTy<'tcx>,
-) -> Result<(), InternResult> {
+) -> Result<(), InternError> {
     let mut disambiguator = DisambiguatorState::new();
 
     // We are interning recursively, and for mutability we are distinguishing the "root" allocation
@@ -181,7 +193,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
         }
         InternKind::Static(Mutability::Not) => {
             (
-                // Outermost allocation is mutable if `!Freeze`.
+                // Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types.
                 if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) {
                     Mutability::Not
                 } else {
@@ -224,6 +236,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
     // We want to first report "dangling" and then "mutable", so we need to delay reporting these
     // errors.
     let mut result = Ok(());
+    let mut found_bad_mutable_ptr = false;
 
     // Keep interning as long as there are things to intern.
     // We show errors if there are dangling pointers, or mutable pointers in immutable contexts
@@ -278,18 +291,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
             // when there is memory there that someone might expect to be mutable, but we make it immutable.
             let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id);
             if !dangling {
-                // Found a mutable pointer inside a const where inner allocations should be
-                // immutable.
-                if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
-                    span_bug!(
-                        ecx.tcx.span,
-                        "the static const safety checks accepted a mutable pointer they should not have accepted"
-                    );
-                }
-                // Prefer dangling pointer errors over mutable pointer errors
-                if result.is_ok() {
-                    result = Err(InternResult::FoundBadMutablePointer);
-                }
+                found_bad_mutable_ptr = true;
             }
         }
         if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
@@ -310,18 +312,31 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
         just_interned.insert(alloc_id);
         match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) {
             Ok(nested) => todo.extend(nested),
-            Err(()) => {
-                ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning");
-                result = Err(InternResult::FoundDanglingPointer);
+            Err(err) => {
+                ecx.tcx.dcx().delayed_bug("error during const interning");
+                result = Err(err);
             }
         }
     }
+    if found_bad_mutable_ptr && result.is_ok() {
+        // We found a mutable pointer inside a const where inner allocations should be immutable,
+        // and there was no other error. This should usually never happen! However, this can happen
+        // in unleash-miri mode, so report it as a normal error then.
+        if ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
+            result = Err(InternError::BadMutablePointer);
+        } else {
+            span_bug!(
+                ecx.tcx.span,
+                "the static const safety checks accepted a mutable pointer they should not have accepted"
+            );
+        }
+    }
     result
 }
 
 /// Intern `ret`. This function assumes that `ret` references no other allocation.
 #[instrument(level = "debug", skip(ecx))]
-pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
+pub fn intern_const_alloc_for_constprop<'tcx, M: CompileTimeMachine<'tcx>>(
     ecx: &mut InterpCx<'tcx, M>,
     alloc_id: AllocId,
 ) -> InterpResult<'tcx, ()> {
@@ -330,10 +345,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>
         return interp_ok(());
     }
     // Move allocation to `tcx`.
-    if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None)
-        .map_err(|()| err_ub!(DeadLocal))?
-        .next()
-    {
+    if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None).unwrap().next() {
         // We are not doing recursive interning, so we don't currently support provenance.
         // (If this assertion ever triggers, we should just implement a
         // proper recursive interning loop -- or just call `intern_const_alloc_recursive`.
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 22d29eda913..e24a355891d 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -4,8 +4,9 @@
 
 use std::assert_matches::assert_matches;
 
-use rustc_abi::{FieldIdx, Size};
+use rustc_abi::{FieldIdx, HasDataLayout, Size};
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
+use rustc_middle::mir::interpret::{read_target_uint, write_target_uint};
 use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -30,7 +31,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
 }
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Generates a value of `TypeId` for `ty` in-place.
-    pub(crate) fn write_type_id(
+    fn write_type_id(
         &mut self,
         ty: Ty<'tcx>,
         dest: &PlaceTy<'tcx, M::Provenance>,
@@ -48,8 +49,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Here we rely on `TypeId` being a newtype around an array of pointers, so we
         // first project to its only field and then the array elements.
         let alloc_id = tcx.reserve_and_set_type_id_alloc(ty);
-        let first = self.project_field(dest, FieldIdx::ZERO)?;
-        let mut elem_iter = self.project_array_fields(&first)?;
+        let arr = self.project_field(dest, FieldIdx::ZERO)?;
+        let mut elem_iter = self.project_array_fields(&arr)?;
         while let Some((_, elem)) = elem_iter.next(self)? {
             // Decorate this part of the hash with provenance; leave the integer part unchanged.
             let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?;
@@ -61,6 +62,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         interp_ok(())
     }
 
+    /// Read a value of type `TypeId`, returning the type it represents.
+    pub(crate) fn read_type_id(
+        &self,
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, Ty<'tcx>> {
+        // `TypeId` is a newtype around an array of pointers. All pointers must have the same
+        // provenance, and that provenance represents the type.
+        let ptr_size = self.pointer_size().bytes_usize();
+        let arr = self.project_field(op, FieldIdx::ZERO)?;
+
+        let mut ty_and_hash = None;
+        let mut elem_iter = self.project_array_fields(&arr)?;
+        while let Some((idx, elem)) = elem_iter.next(self)? {
+            let elem = self.read_pointer(&elem)?;
+            let (elem_ty, elem_hash) = self.get_ptr_type_id(elem)?;
+            // If this is the first element, remember the type and its hash.
+            // If this is not the first element, ensure it is consistent with the previous ones.
+            let full_hash = match ty_and_hash {
+                None => {
+                    let hash = self.tcx.type_id_hash(elem_ty).as_u128();
+                    let mut hash_bytes = [0u8; 16];
+                    write_target_uint(self.data_layout().endian, &mut hash_bytes, hash).unwrap();
+                    ty_and_hash = Some((elem_ty, hash_bytes));
+                    hash_bytes
+                }
+                Some((ty, hash_bytes)) => {
+                    if ty != elem_ty {
+                        throw_ub_format!(
+                            "invalid `TypeId` value: not all bytes carry the same type id metadata"
+                        );
+                    }
+                    hash_bytes
+                }
+            };
+            // Ensure the elem_hash matches the corresponding part of the full hash.
+            let hash_frag = &full_hash[(idx as usize) * ptr_size..][..ptr_size];
+            if read_target_uint(self.data_layout().endian, hash_frag).unwrap() != elem_hash.into() {
+                throw_ub_format!(
+                    "invalid `TypeId` value: the hash does not match the type id metadata"
+                );
+            }
+        }
+
+        interp_ok(ty_and_hash.unwrap().0)
+    }
+
     /// Returns `true` if emulation happened.
     /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
     /// intrinsic handling.
@@ -97,47 +144,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_type_id(tp_ty, dest)?;
             }
             sym::type_id_eq => {
-                // Both operands are `TypeId`, which is a newtype around an array of pointers.
-                // Project until we have the array elements.
-                let a_fields = self.project_field(&args[0], FieldIdx::ZERO)?;
-                let b_fields = self.project_field(&args[1], FieldIdx::ZERO)?;
-
-                let mut a_fields = self.project_array_fields(&a_fields)?;
-                let mut b_fields = self.project_array_fields(&b_fields)?;
-
-                let mut provenance_a = None;
-                let mut provenance_b = None;
-                let mut provenance_matches = true;
-
-                while let Some((i, a)) = a_fields.next(self)? {
-                    let (_, b) = b_fields.next(self)?.unwrap();
-
-                    let a = self.deref_pointer(&a)?;
-                    let (a, offset_a) = self.get_ptr_type_id(a.ptr())?;
-
-                    let b = self.deref_pointer(&b)?;
-                    let (b, offset_b) = self.get_ptr_type_id(b.ptr())?;
-
-                    if *provenance_a.get_or_insert(a) != a {
-                        throw_ub_format!(
-                            "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
-                        )
-                    }
-                    if *provenance_b.get_or_insert(b) != b {
-                        throw_ub_format!(
-                            "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
-                        )
-                    }
-                    provenance_matches &= a == b;
-
-                    if offset_a != offset_b && provenance_matches {
-                        throw_ub_format!(
-                            "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents"
-                        )
-                    }
-                }
-
-                self.write_scalar(Scalar::from_bool(provenance_matches), dest)?;
+                let a_ty = self.read_type_id(&args[0])?;
+                let b_ty = self.read_type_id(&args[1])?;
+                self.write_scalar(Scalar::from_bool(a_ty == b_ty), dest)?;
             }
             sym::variant_count => {
                 let tp_ty = instance.args.type_at(0);
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index d150ed69250..e981f3973ae 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -649,6 +649,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
 
     type ExtraFnVal = !;
 
+    type MemoryKind = $crate::const_eval::MemoryKind;
     type MemoryMap =
         rustc_data_structures::fx::FxIndexMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
     const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 6414821e21d..20c8e983cea 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -26,6 +26,7 @@ use super::{
     Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
     err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
 };
+use crate::const_eval::ConstEvalErrKind;
 use crate::fluent_generated as fluent;
 
 #[derive(Debug, PartialEq, Copy, Clone)]
@@ -66,8 +67,8 @@ pub enum AllocKind {
     LiveData,
     /// A function allocation (that fn ptrs point to).
     Function,
-    /// A (symbolic) vtable allocation.
-    VTable,
+    /// A "virtual" allocation, used for vtables and TypeId.
+    Virtual,
     /// A dead allocation.
     Dead,
 }
@@ -311,6 +312,51 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         interp_ok(new_ptr)
     }
 
+    /// Mark the `const_allocate`d allocation `ptr` points to as immutable so we can intern it.
+    pub fn make_const_heap_ptr_global(
+        &mut self,
+        ptr: Pointer<Option<CtfeProvenance>>,
+    ) -> InterpResult<'tcx>
+    where
+        M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind, Provenance = CtfeProvenance>,
+    {
+        let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?;
+        if offset.bytes() != 0 {
+            return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(ptr)).into();
+        }
+
+        if matches!(self.tcx.try_get_global_alloc(alloc_id), Some(_)) {
+            // This points to something outside the current interpreter.
+            return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into();
+        }
+
+        // If we can't find it in `alloc_map` it must be dangling (because we don't use
+        // `extra_fn_ptr_map` in const-eval).
+        let (kind, alloc) = self
+            .memory
+            .alloc_map
+            .get_mut_or(alloc_id, || Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(ptr)))?;
+
+        // Ensure this is actually a *heap* allocation, and record it as made-global.
+        match kind {
+            MemoryKind::Stack | MemoryKind::CallerLocation => {
+                return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into();
+            }
+            MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => {
+                if *was_made_global {
+                    return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id))
+                        .into();
+                }
+                *was_made_global = true;
+            }
+        }
+
+        // Prevent further mutation, this is now an immutable global.
+        alloc.mutability = Mutability::Not;
+
+        interp_ok(())
+    }
+
     #[instrument(skip(self), level = "debug")]
     pub fn deallocate_ptr(
         &mut self,
@@ -890,7 +936,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if let Some(fn_val) = self.get_fn_alloc(id) {
             let align = match fn_val {
                 FnVal::Instance(instance) => {
-                    self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE)
+                    self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE)
                 }
                 // Machine-specific extra functions currently do not support alignment restrictions.
                 FnVal::Other(_) => Align::ONE,
@@ -904,11 +950,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env);
             let mutbl = global_alloc.mutability(*self.tcx, self.typing_env);
             let kind = match global_alloc {
-                GlobalAlloc::TypeId { .. }
-                | GlobalAlloc::Static { .. }
-                | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
+                GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
                 GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
-                GlobalAlloc::VTable { .. } => AllocKind::VTable,
+                GlobalAlloc::VTable { .. } | GlobalAlloc::TypeId { .. } => AllocKind::Virtual,
             };
             return AllocInfo::new(size, align, kind, mutbl);
         }
@@ -951,12 +995,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn get_ptr_type_id(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
-    ) -> InterpResult<'tcx, (Ty<'tcx>, Size)> {
+    ) -> InterpResult<'tcx, (Ty<'tcx>, u64)> {
         let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?;
         let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else {
-            throw_ub_format!("type_id_eq: `TypeId` provenance is not a type id")
+            throw_ub_format!("invalid `TypeId` value: not all bytes carry type id metadata")
         };
-        interp_ok((ty, offset))
+        interp_ok((ty, offset.bytes()))
     }
 
     pub fn get_ptr_fn(
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index 2fc372dd019..2f365ec77b3 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -26,7 +26,7 @@ pub use self::call::FnArg;
 pub use self::eval_context::{InterpCx, format_interp_error};
 use self::eval_context::{from_known_layout, mir_assign_valid_types};
 pub use self::intern::{
-    HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop,
+    HasStaticRootDefId, InternError, InternKind, intern_const_alloc_for_constprop,
     intern_const_alloc_recursive,
 };
 pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index b6ba069526c..2e99bb4209f 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_mir_dataflow::impls::always_storage_live_locals;
 use rustc_span::Span;
+use tracing::field::Empty;
 use tracing::{info_span, instrument, trace};
 
 use super::{
@@ -396,7 +397,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Finish things up.
         M::after_stack_push(self)?;
         self.frame_mut().loc = Left(mir::Location::START);
-        let span = info_span!("frame", "{}", instance);
+        // `tracing_separate_thread` is used to instruct the chrome_tracing [tracing::Layer] in Miri
+        // to put the "frame" span on a separate trace thread/line than other spans, to make the
+        // visualization in https://ui.perfetto.dev easier to interpret. It is set to a value of
+        // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it.
+        let span = info_span!("frame", tracing_separate_thread = Empty, "{}", instance);
         self.frame_mut().tracing_span.enter(span);
 
         interp_ok(())
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index fc44490c96d..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(_)) =>
@@ -558,7 +558,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 {
                     // Everything should be already interned.
                     let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else {
-                        assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none());
+                        if self.ecx.memory.alloc_map.contains_key(&alloc_id) {
+                            // This can happen when interning didn't complete due to, e.g.
+                            // missing `make_global`. This must mean other errors are already
+                            // being reported.
+                            self.ecx.tcx.dcx().delayed_bug(
+                                "interning did not complete, there should be an error",
+                            );
+                            return interp_ok(());
+                        }
                         // We can't have *any* references to non-existing allocations in const-eval
                         // as the rest of rustc isn't happy with them... so we throw an error, even
                         // though for zero-sized references this isn't really UB.
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 4ca39bbc68e..b1f29598750 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -52,9 +52,9 @@ fn check_validity_requirement_strict<'tcx>(
 
     let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine);
 
-    let allocated = cx
-        .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
-        .expect("OOM: failed to allocate for uninit check");
+    // It doesn't really matter which `MemoryKind` we use here, `Stack` is the least wrong.
+    let allocated =
+        cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check");
 
     if kind == ValidityRequirement::Zero {
         cx.write_bytes_ptr(
@@ -184,9 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>(
     let Ok(layout) = cx.layout_of(ty) else {
         bug!("could not compute layout of {scalar:?}:{ty:?}")
     };
-    let allocated = cx
-        .allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
-        .expect("OOM: failed to allocate for uninit check");
+
+    // It doesn't really matter which `MemoryKind` we use here, `Stack` is the least wrong.
+    let allocated =
+        cx.allocate(layout, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check");
 
     cx.write_scalar(scalar, &allocated).unwrap();
 
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 18490385455..f3ed6042105 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1237,9 +1237,55 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
         return None;
     }
 
+    warn_on_confusing_output_filename_flag(early_dcx, &matches, args);
+
     Some(matches)
 }
 
+/// Warn if `-o` is used without a space between the flag name and the value
+/// and the value is a high-value confusables,
+/// e.g. `-optimize` instead of `-o optimize`, see issue #142812.
+fn warn_on_confusing_output_filename_flag(
+    early_dcx: &EarlyDiagCtxt,
+    matches: &getopts::Matches,
+    args: &[String],
+) {
+    fn eq_ignore_separators(s1: &str, s2: &str) -> bool {
+        let s1 = s1.replace('-', "_");
+        let s2 = s2.replace('-', "_");
+        s1 == s2
+    }
+
+    if let Some(name) = matches.opt_str("o")
+        && let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
+    {
+        let filename = suspect.strip_prefix("-").unwrap_or(suspect);
+        let optgroups = config::rustc_optgroups();
+        let fake_args = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
+
+        // Check if provided filename might be confusing in conjunction with `-o` flag,
+        // i.e. consider `-o{filename}` such as `-optimize` with `filename` being `ptimize`.
+        // There are high-value confusables, for example:
+        // - Long name of flags, e.g. `--out-dir` vs `-out-dir`
+        // - C compiler flag, e.g. `optimize`, `o0`, `o1`, `o2`, `o3`, `ofast`.
+        // - Codegen flags, e.g. `pt-level` of `-opt-level`.
+        if optgroups.iter().any(|option| eq_ignore_separators(option.long_name(), filename))
+            || config::CG_OPTIONS.iter().any(|option| eq_ignore_separators(option.name(), filename))
+            || fake_args.iter().any(|arg| eq_ignore_separators(arg, filename))
+        {
+            early_dcx.early_warn(
+                "option `-o` has no space between flag name and value, which can be confusing",
+            );
+            early_dcx.early_note(format!(
+                "output filename `-o {name}` is applied instead of a flag named `o{name}`"
+            ));
+            early_dcx.early_help(format!(
+                "insert a space between `-o` and `{name}` if this is intentional: `-o {name}`"
+            ));
+        }
+    }
+}
+
 fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
     let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
         Input::File(file) => new_parser_from_file(&sess.psess, file, None),
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_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index ce3006c2604..1928cfd9048 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1062,7 +1062,7 @@ pub trait ResolverExpand {
     fn next_node_id(&mut self) -> NodeId;
     fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId;
 
-    fn resolve_dollar_crates(&mut self);
+    fn resolve_dollar_crates(&self);
     fn visit_ast_fragment_with_placeholders(
         &mut self,
         expn_id: LocalExpnId,
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 85683c1a03f..51d6e43ab67 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -3,8 +3,8 @@ use rustc_ast::token::Delimiter;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::literal;
 use rustc_ast::{
-    self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp,
-    attr, token, tokenstream,
+    self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind,
+    UnOp, attr, token, tokenstream,
 };
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
@@ -766,4 +766,10 @@ impl<'a> ExtCtxt<'a> {
             span,
         )
     }
+
+    // Builds an attribute fully manually.
+    pub fn attr_nested(&self, inner: AttrItem, span: Span) -> ast::Attribute {
+        let g = &self.sess.psess.attr_id_generator;
+        attr::mk_attr_from_item(g, inner, None, ast::AttrStyle::Outer, span)
+    }
 }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 6922ddfd6bd..83a8d601afe 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -12,7 +12,7 @@ use rustc_ast::{
 };
 use rustc_attr_parsing as attr;
 use rustc_attr_parsing::{
-    AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr,
+    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr,
 };
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::{
@@ -167,7 +167,9 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
         .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
         .take_while(|attr| {
             !is_cfg(attr)
-                || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool()
+                || strip_unconfigured
+                    .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing)
+                    .as_bool()
         })
         .collect()
 }
@@ -401,10 +403,18 @@ impl<'a> StripUnconfigured<'a> {
 
     /// Determines if a node with the given attributes should be included in this configuration.
     fn in_cfg(&self, attrs: &[Attribute]) -> bool {
-        attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool())
+        attrs.iter().all(|attr| {
+            !is_cfg(attr)
+                || self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool()
+        })
     }
 
-    pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult {
+    pub(crate) fn cfg_true(
+        &self,
+        attr: &Attribute,
+        node: NodeId,
+        emit_errors: ShouldEmit,
+    ) -> EvalConfigResult {
         // We need to run this to do basic validation of the attribute, such as that lits are valid, etc
         // FIXME(jdonszelmann) this should not be necessary in the future
         match validate_attr::parse_meta(&self.sess.psess, attr) {
@@ -428,7 +438,7 @@ impl<'a> StripUnconfigured<'a> {
             attr.span,
             node,
             self.features,
-            true,
+            emit_errors,
             parse_cfg_attr,
             &CFG_TEMPLATE,
         ) else {
@@ -436,7 +446,7 @@ impl<'a> StripUnconfigured<'a> {
             return EvalConfigResult::True;
         };
 
-        eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features)
+        eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features, emit_errors)
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index f99060e9a21..79ec79a2fdf 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -13,7 +13,7 @@ use rustc_ast::{
     MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
 };
 use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::EvalConfigResult;
+use rustc_attr_parsing::{EvalConfigResult, ShouldEmit};
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_errors::PResult;
 use rustc_feature::Features;
@@ -2171,7 +2171,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         attr: ast::Attribute,
         pos: usize,
     ) -> EvalConfigResult {
-        let res = self.cfg().cfg_true(&attr, node.node_id());
+        let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints);
         if res.as_bool() {
             // A trace attribute left in AST in place of the original `cfg` attribute.
             // It can later be used by lints or other diagnostics.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 7d9915d7f68..74872504b79 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -614,6 +614,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // RFC 2632
+    // FIXME(const_trait_impl) remove this
     gated!(
         const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl,
         "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \
@@ -684,6 +685,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::Yes
     ),
     ungated!(
+        unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."),
+        DuplicatesOk, EncodeCrossCrate::No,
+    ),
+    ungated!(
         rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
         DuplicatesOk, EncodeCrossCrate::Yes
     ),
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index f93b9e5af53..698406d53a4 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -140,7 +140,9 @@ impl DefKey {
     pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash {
         let mut hasher = StableHasher::new();
 
-        parent.hash(&mut hasher);
+        // The new path is in the same crate as `parent`, and will contain the stable_crate_id.
+        // Therefore, we only need to include information of the parent's local hash.
+        parent.local_hash().hash(&mut hasher);
 
         let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
 
@@ -181,32 +183,26 @@ pub struct DisambiguatedDefPathData {
 }
 
 impl DisambiguatedDefPathData {
-    pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result {
+    pub fn as_sym(&self, verbose: bool) -> Symbol {
         match self.data.name() {
             DefPathDataName::Named(name) => {
                 if verbose && self.disambiguator != 0 {
-                    write!(writer, "{}#{}", name, self.disambiguator)
+                    Symbol::intern(&format!("{}#{}", name, self.disambiguator))
                 } else {
-                    writer.write_str(name.as_str())
+                    name
                 }
             }
             DefPathDataName::Anon { namespace } => {
                 if let DefPathData::AnonAssocTy(method) = self.data {
-                    write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator)
+                    Symbol::intern(&format!("{}::{{{}#{}}}", method, namespace, self.disambiguator))
                 } else {
-                    write!(writer, "{{{}#{}}}", namespace, self.disambiguator)
+                    Symbol::intern(&format!("{{{}#{}}}", namespace, self.disambiguator))
                 }
             }
         }
     }
 }
 
-impl fmt::Display for DisambiguatedDefPathData {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.fmt_maybe_verbose(f, true)
-    }
-}
-
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub struct DefPath {
     /// The path leading from the crate root to the item.
@@ -250,7 +246,7 @@ impl DefPath {
         let mut s = String::with_capacity(self.data.len() * 16);
 
         for component in &self.data {
-            write!(s, "::{component}").unwrap();
+            write!(s, "::{}", component.as_sym(true)).unwrap();
         }
 
         s
@@ -266,7 +262,7 @@ impl DefPath {
         for component in &self.data {
             s.extend(opt_delimiter);
             opt_delimiter = Some('-');
-            write!(s, "{component}").unwrap();
+            write!(s, "{}", component.as_sym(true)).unwrap();
         }
 
         s
@@ -361,8 +357,16 @@ impl Definitions {
             },
         };
 
-        let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO);
-        let def_path_hash = key.compute_stable_hash(parent_hash);
+        // We want *both* halves of a DefPathHash to depend on the crate-id of the defining crate.
+        // The crate-id can be more easily changed than the DefPath of an item, so, in the case of
+        // a crate-local DefPathHash collision, the user can simply "roll the dice again" for all
+        // DefPathHashes in the crate by changing the crate disambiguator (e.g. via bumping the
+        // crate's version number).
+        //
+        // Children paths will only hash the local portion, and still inherit the change to the
+        // root hash.
+        let def_path_hash =
+            DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64()));
 
         // Create the root definition.
         let mut table = DefPathTable::new(stable_crate_id);
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 159518a8d87..e7898648c2b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -7,7 +7,7 @@ use rustc_ast::token::CommentKind;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_ast::{
     self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType,
-    LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind,
+    LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, join_path_idents,
 };
 pub use rustc_ast::{
     AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind,
@@ -1168,7 +1168,7 @@ impl AttrPath {
 
 impl fmt::Display for AttrPath {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::<Vec<_>>().join("::"))
+        write!(f, "{}", join_path_idents(&self.segments))
     }
 }
 
@@ -4163,6 +4163,7 @@ impl<'hir> Item<'hir> {
 
         expect_trait,
             (
+                Constness,
                 IsAuto,
                 Safety,
                 Ident,
@@ -4170,8 +4171,8 @@ impl<'hir> Item<'hir> {
                 GenericBounds<'hir>,
                 &'hir [TraitItemId]
             ),
-            ItemKind::Trait(is_auto, safety, ident, generics, bounds, items),
-            (*is_auto, *safety, *ident, generics, bounds, items);
+            ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items),
+            (*constness, *is_auto, *safety, *ident, generics, bounds, items);
 
         expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
             ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
@@ -4341,7 +4342,15 @@ pub enum ItemKind<'hir> {
     /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
     Union(Ident, &'hir Generics<'hir>, VariantData<'hir>),
     /// A trait definition.
-    Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemId]),
+    Trait(
+        Constness,
+        IsAuto,
+        Safety,
+        Ident,
+        &'hir Generics<'hir>,
+        GenericBounds<'hir>,
+        &'hir [TraitItemId],
+    ),
     /// A trait alias.
     TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
 
@@ -4385,7 +4394,7 @@ impl ItemKind<'_> {
             | ItemKind::Enum(ident, ..)
             | ItemKind::Struct(ident, ..)
             | ItemKind::Union(ident, ..)
-            | ItemKind::Trait(_, _, ident, ..)
+            | ItemKind::Trait(_, _, _, ident, ..)
             | ItemKind::TraitAlias(ident, ..) => Some(ident),
 
             ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
@@ -4403,7 +4412,7 @@ impl ItemKind<'_> {
             | ItemKind::Enum(_, generics, _)
             | ItemKind::Struct(_, generics, _)
             | ItemKind::Union(_, generics, _)
-            | ItemKind::Trait(_, _, _, generics, _, _)
+            | ItemKind::Trait(_, _, _, _, generics, _, _)
             | ItemKind::TraitAlias(_, generics, _)
             | ItemKind::Impl(Impl { generics, .. }) => generics,
             _ => return None,
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 3edb94c28da..f33915d5b07 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -618,7 +618,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_generics(generics));
             try_visit!(visitor.visit_variant_data(struct_definition));
         }
-        ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => {
+        ItemKind::Trait(
+            _constness,
+            _is_auto,
+            _safety,
+            ident,
+            ref generics,
+            bounds,
+            trait_item_refs,
+        ) => {
             try_visit!(visitor.visit_ident(ident));
             try_visit!(visitor.visit_generics(generics));
             walk_list!(visitor, visit_param_bound, bounds);
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 601898023fc..d617f44f8d8 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -41,7 +41,7 @@ pub enum Target {
     Union,
     Trait,
     TraitAlias,
-    Impl,
+    Impl { of_trait: bool },
     Expression,
     Statement,
     Arm,
@@ -51,7 +51,7 @@ pub enum Target {
     ForeignFn,
     ForeignStatic,
     ForeignTy,
-    GenericParam(GenericParamKind),
+    GenericParam { kind: GenericParamKind, has_default: bool },
     MacroDef,
     Param,
     PatField,
@@ -86,14 +86,14 @@ impl Target {
             | Target::Union
             | Target::Trait
             | Target::TraitAlias
-            | Target::Impl
+            | Target::Impl { .. }
             | Target::Expression
             | Target::Statement
             | Target::Arm
             | Target::ForeignFn
             | Target::ForeignStatic
             | Target::ForeignTy
-            | Target::GenericParam(_)
+            | Target::GenericParam { .. }
             | Target::MacroDef
             | Target::Param
             | Target::PatField
@@ -119,7 +119,7 @@ impl Target {
             ItemKind::Union(..) => Target::Union,
             ItemKind::Trait(..) => Target::Trait,
             ItemKind::TraitAlias(..) => Target::TraitAlias,
-            ItemKind::Impl { .. } => Target::Impl,
+            ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() },
         }
     }
 
@@ -141,7 +141,7 @@ impl Target {
             DefKind::Union => Target::Union,
             DefKind::Trait => Target::Trait,
             DefKind::TraitAlias => Target::TraitAlias,
-            DefKind::Impl { .. } => Target::Impl,
+            DefKind::Impl { of_trait } => Target::Impl { of_trait },
             _ => panic!("impossible case reached"),
         }
     }
@@ -169,11 +169,17 @@ impl Target {
 
     pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target {
         match generic_param.kind {
-            hir::GenericParamKind::Type { .. } => Target::GenericParam(GenericParamKind::Type),
+            hir::GenericParamKind::Type { default, .. } => Target::GenericParam {
+                kind: GenericParamKind::Type,
+                has_default: default.is_some(),
+            },
             hir::GenericParamKind::Lifetime { .. } => {
-                Target::GenericParam(GenericParamKind::Lifetime)
+                Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }
             }
-            hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const),
+            hir::GenericParamKind::Const { default, .. } => Target::GenericParam {
+                kind: GenericParamKind::Const,
+                has_default: default.is_some(),
+            },
         }
     }
 
@@ -196,7 +202,8 @@ impl Target {
             Target::Union => "union",
             Target::Trait => "trait",
             Target::TraitAlias => "trait alias",
-            Target::Impl => "implementation block",
+            Target::Impl { of_trait: false } => "inherent implementation block",
+            Target::Impl { of_trait: true } => "trait implementation block",
             Target::Expression => "expression",
             Target::Statement => "statement",
             Target::Arm => "match arm",
@@ -210,7 +217,7 @@ impl Target {
             Target::ForeignFn => "foreign function",
             Target::ForeignStatic => "foreign static item",
             Target::ForeignTy => "foreign type",
-            Target::GenericParam(kind) => match kind {
+            Target::GenericParam { kind, has_default: _ } => match kind {
                 GenericParamKind::Type => "type parameter",
                 GenericParamKind::Lifetime => "lifetime parameter",
                 GenericParamKind::Const => "const parameter",
diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs
index 18c2bfdac8c..3b797c1f103 100644
--- a/compiler/rustc_hir/src/tests.rs
+++ b/compiler/rustc_hir/src/tests.rs
@@ -28,7 +28,8 @@ fn def_path_hash_depends_on_crate_id() {
         assert_ne!(h0.local_hash(), h1.local_hash());
 
         fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
-            let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO);
+            let parent_hash =
+                DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64()));
 
             let key = DefKey {
                 parent: None,
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 529d3578985..2428c1aa29f 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -117,15 +117,15 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s
 
 hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found
 
-hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits
+hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `const` traits
     .label = can't be applied to `{$trait_name}`
-    .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]`
-    .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations
+    .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't `const`
+    .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations
 
-hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
+hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not `const`
     .label = this trait is not `const`
-    .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations
-    .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+    .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations
+    .note = marking a trait with `const` ensures all default method bodies are `const`
     .adding = adding a non-const method body in the future would be a breaking change
 
 hir_analysis_const_param_ty_impl_on_non_adt =
@@ -158,7 +158,7 @@ hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be imp
 hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
 
 hir_analysis_drop_impl_on_wrong_item =
-    the `Drop` trait may only be implemented for local structs, enums, and unions
+    the `{$trait_}` trait may only be implemented for local structs, enums, and unions
     .label = must be a struct, enum, or union in the current crate
 
 hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
@@ -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/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 70fbb8a543e..03c026cd6c8 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -889,8 +889,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
             tcx.ensure_ok().predicates_of(def_id);
             tcx.ensure_ok().explicit_item_bounds(def_id);
             tcx.ensure_ok().explicit_item_self_bounds(def_id);
-            tcx.ensure_ok().item_bounds(def_id);
-            tcx.ensure_ok().item_self_bounds(def_id);
             if tcx.is_conditionally_const(def_id) {
                 tcx.ensure_ok().explicit_implied_const_bounds(def_id);
                 tcx.ensure_ok().const_conditions(def_id);
@@ -1044,8 +1042,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
             let has_type = match assoc_item.container {
                 ty::AssocItemContainer::Impl => true,
                 ty::AssocItemContainer::Trait => {
-                    tcx.ensure_ok().item_bounds(def_id);
-                    tcx.ensure_ok().item_self_bounds(def_id);
+                    tcx.ensure_ok().explicit_item_bounds(def_id);
+                    tcx.ensure_ok().explicit_item_self_bounds(def_id);
+                    if tcx.is_conditionally_const(def_id) {
+                        tcx.ensure_ok().explicit_implied_const_bounds(def_id);
+                        tcx.ensure_ok().const_conditions(def_id);
+                    }
                     res = res.and(check_trait_item(tcx, def_id));
                     assoc_item.defaultness(tcx).has_value()
                 }
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/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index dcab6ef1c5a..6e5fe3823ab 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -422,6 +422,9 @@ pub(crate) fn check_intrinsic_type(
             vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
             tcx.types.unit,
         ),
+        sym::const_make_global => {
+            (0, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8))
+        }
 
         sym::ptr_offset_from => (
             1,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 607028f4d9a..14ec82ede1c 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -2212,12 +2212,16 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
         let implied_obligations = traits::elaborate(tcx, predicates_with_span);
 
         for (pred, obligation_span) in implied_obligations {
-            // We lower empty bounds like `Vec<dyn Copy>:` as
-            // `WellFormed(Vec<dyn Copy>)`, which will later get checked by
-            // regular WF checking
-            if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
-                continue;
+            match pred.kind().skip_binder() {
+                // We lower empty bounds like `Vec<dyn Copy>:` as
+                // `WellFormed(Vec<dyn Copy>)`, which will later get checked by
+                // regular WF checking
+                ty::ClauseKind::WellFormed(..)
+                // Unstable feature goals cannot be proven in an empty environment so skip them
+                | ty::ClauseKind::UnstableFeature(..) => continue,
+                _ => {}
             }
+
             // Match the existing behavior.
             if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
                 let pred = self.normalize(span, None, pred);
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 8356a0af63c..27948f50a4a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -37,6 +37,7 @@ pub(super) fn check_trait<'tcx>(
     let lang_items = tcx.lang_items();
     let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
     checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
+    checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?;
     checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
     checker.check(lang_items.const_param_ty_trait(), |checker| {
         visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
@@ -83,7 +84,10 @@ fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaran
 
     let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
 
-    Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
+    Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem {
+        span: impl_.self_ty.span,
+        trait_: tcx.item_name(checker.impl_header.trait_ref.skip_binder().def_id),
+    }))
 }
 
 fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 28a8758178f..0728b24eb14 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -844,15 +844,20 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let item = tcx.hir_expect_item(def_id);
 
-    let (is_alias, is_auto, safety) = match item.kind {
-        hir::ItemKind::Trait(is_auto, safety, ..) => (false, is_auto == hir::IsAuto::Yes, safety),
-        hir::ItemKind::TraitAlias(..) => (true, false, hir::Safety::Safe),
+    let (constness, is_alias, is_auto, safety) = match item.kind {
+        hir::ItemKind::Trait(constness, is_auto, safety, ..) => {
+            (constness, false, is_auto == hir::IsAuto::Yes, safety)
+        }
+        hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
     let attrs = tcx.get_all_attrs(def_id);
     // Only regular traits can be const.
-    let constness = if !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) {
+    // FIXME(const_trait_impl): remove this
+    let constness = if constness == hir::Constness::Const
+        || !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_))
+    {
         hir::Constness::Const
     } else {
         hir::Constness::NotConst
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index e51ef46afb7..548ba343aae 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -38,12 +38,13 @@ fn associated_type_bounds<'tcx>(
         let icx = ItemCtxt::new(tcx, assoc_item_def_id);
         let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
-        // Implicit bounds are added to associated types unless a `?Trait` bound is found
+
         match filter {
             PredicateFilter::All
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                // Implicit bounds are added to associated types unless a `?Trait` bound is found.
                 icx.lowerer().add_sizedness_bounds(
                     &mut bounds,
                     item_ty,
@@ -53,37 +54,48 @@ fn associated_type_bounds<'tcx>(
                     span,
                 );
                 icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
+
+                // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses.
+                let trait_def_id = tcx.local_parent(assoc_item_def_id);
+                let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
+
+                let item_trait_ref =
+                    ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id()));
+                bounds.extend(trait_predicates.predicates.iter().copied().filter_map(
+                    |(clause, span)| {
+                        remap_gat_vars_and_recurse_into_nested_projections(
+                            tcx,
+                            filter,
+                            item_trait_ref,
+                            assoc_item_def_id,
+                            span,
+                            clause,
+                        )
+                    },
+                ));
             }
             // `ConstIfConst` is only interested in `[const]` bounds.
-            PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+            PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {
+                // FIXME(const_trait_impl): We *could* uplift the
+                // `where Self::Assoc: [const] Trait` bounds from the parent trait
+                // here too, but we'd need to split `const_conditions` into two
+                // queries (like we do for `trait_explicit_predicates_and_bounds`)
+                // since we need to also filter the predicates *out* of the const
+                // conditions or they lead to cycles in the trait solver when
+                // utilizing these bounds. For now, let's do nothing.
+            }
         }
 
-        let trait_def_id = tcx.local_parent(assoc_item_def_id);
-        let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
-
-        let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id()));
-        let bounds_from_parent =
-            trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| {
-                remap_gat_vars_and_recurse_into_nested_projections(
-                    tcx,
-                    filter,
-                    item_trait_ref,
-                    assoc_item_def_id,
-                    span,
-                    clause,
-                )
-            });
-
-        let all_bounds = tcx.arena.alloc_from_iter(bounds.into_iter().chain(bounds_from_parent));
+        let bounds = tcx.arena.alloc_from_iter(bounds);
         debug!(
             "associated_type_bounds({}) = {:?}",
             tcx.def_path_str(assoc_item_def_id.to_def_id()),
-            all_bounds
+            bounds
         );
 
-        assert_only_contains_predicates_from(filter, all_bounds, item_ty);
+        assert_only_contains_predicates_from(filter, bounds, item_ty);
 
-        all_bounds
+        bounds
     })
 }
 
@@ -112,6 +124,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
         ty::ClauseKind::Trait(tr) => tr.self_ty(),
         ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(),
         ty::ClauseKind::TypeOutlives(outlives) => outlives.0,
+        ty::ClauseKind::HostEffect(host) => host.self_ty(),
         _ => return None,
     };
 
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index a93e58b101f..cc53919626e 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,6 +1,7 @@
 use std::assert_matches::assert_matches;
 
 use hir::Node;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -162,7 +163,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                         .map(|t| ty::Binder::dummy(t.instantiate_identity()));
                 }
             }
-            ItemKind::Trait(_, _, _, _, self_bounds, ..)
+            ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
             | ItemKind::TraitAlias(_, _, self_bounds) => {
                 is_trait = Some((self_bounds, item.span));
             }
@@ -266,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()),
@@ -333,6 +330,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates));
     }
 
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
+    // FIXME(staged_api): We might want to look at the normal stability attributes too but
+    // first we would need a way to let std/core use APIs with unstable feature bounds from
+    // within stable APIs.
+    let allow_unstable_feature_attr =
+        find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i)
+            .map(|i| i.as_slice())
+            .unwrap_or_default();
+
+    for (feat_name, span) in allow_unstable_feature_attr {
+        predicates.insert((ty::ClauseKind::UnstableFeature(*feat_name).upcast(tcx), *span));
+    }
+
     let mut predicates: Vec<_> = predicates.into_iter().collect();
 
     // Subtle: before we store the predicates into the tcx, we
@@ -764,6 +774,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
                     ty::ClauseKind::RegionOutlives(_)
                     | ty::ClauseKind::ConstArgHasType(_, _)
                     | ty::ClauseKind::WellFormed(_)
+                    | ty::ClauseKind::UnstableFeature(_)
                     | ty::ClauseKind::ConstEvaluatable(_) => {
                         bug!(
                             "unexpected non-`Self` predicate when computing \
@@ -791,6 +802,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
                     | ty::ClauseKind::ConstArgHasType(_, _)
                     | ty::ClauseKind::WellFormed(_)
                     | ty::ClauseKind::ConstEvaluatable(_)
+                    | ty::ClauseKind::UnstableFeature(_)
                     | ty::ClauseKind::HostEffect(..) => {
                         bug!(
                             "unexpected non-`Self` predicate when computing \
@@ -1006,7 +1018,7 @@ pub(super) fn const_conditions<'tcx>(
         Node::Item(item) => match item.kind {
             hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
             hir::ItemKind::Fn { generics, .. } => (generics, None, false),
-            hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => {
+            hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => {
                 (generics, Some((item.owner_id.def_id, supertraits)), false)
             }
             _ => bug!("const_conditions called on wrong item: {def_id:?}"),
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 8d7ac7db67b..eb3492f5de6 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -634,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             | hir::ItemKind::Enum(_, generics, _)
             | hir::ItemKind::Struct(_, generics, _)
             | hir::ItemKind::Union(_, generics, _)
-            | hir::ItemKind::Trait(_, _, _, generics, ..)
+            | hir::ItemKind::Trait(_, _, _, _, generics, ..)
             | hir::ItemKind::TraitAlias(_, generics, ..)
             | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
                 // These kinds of items have only early-bound lifetime parameters.
@@ -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 c1c82839212..26a98722b34 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -205,6 +205,7 @@ pub(crate) struct DropImplOnWrongItem {
     #[primary_span]
     #[label]
     pub span: Span,
+    pub trait_: Symbol,
 }
 
 #[derive(Diagnostic)]
@@ -279,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]
@@ -319,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]
@@ -525,6 +512,7 @@ pub(crate) struct ConstImplForNonConstTrait {
     pub trait_name: String,
     #[suggestion(
         applicability = "machine-applicable",
+        // FIXME(const_trait_impl) fix this suggestion
         code = "#[const_trait] ",
         style = "verbose"
     )]
@@ -548,6 +536,7 @@ pub(crate) struct ConstBoundForNonConstTrait {
     pub suggestion_pre: &'static str,
     #[suggestion(
         applicability = "machine-applicable",
+        // FIXME(const_trait_impl) fix this suggestion
         code = "#[const_trait] ",
         style = "verbose"
     )]
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 3f928fd056e..2d60c9561a9 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -635,7 +635,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                 self.suggest_adding_type_and_const_args(err);
             }
             ExcessTypesOrConsts { .. } => {
-                // this can happen with `[const] T` where T isn't a const_trait.
+                // this can happen with `[const] T` where T isn't a `const trait`.
             }
             _ => unreachable!(),
         }
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 4784cfb5235..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);
             }
         }
@@ -334,7 +329,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
 
         let (trait_generics, trait_bounds) = match parent_trait.kind {
-            hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
+            hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits),
             hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
             _ => unreachable!(),
         };
@@ -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..d7687998358 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",
@@ -2489,6 +2495,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     ty::List::empty(),
                     PredicateFilter::All,
                 );
+                self.add_sizedness_bounds(
+                    &mut bounds,
+                    self_ty,
+                    hir_bounds,
+                    None,
+                    None,
+                    hir_ty.span,
+                );
                 self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span);
                 self_ty
             }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 574d19a5aa5..0043f0c7117 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -499,6 +499,7 @@ fn trait_specialization_kind<'tcx>(
         | ty::ClauseKind::ConstArgHasType(..)
         | ty::ClauseKind::WellFormed(_)
         | ty::ClauseKind::ConstEvaluatable(..)
+        | ty::ClauseKind::UnstableFeature(_)
         | ty::ClauseKind::HostEffect(..) => None,
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 2c1d443f951..d3a57a4d8e5 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::ClauseKind::ConstArgHasType(_, _)
                     | ty::ClauseKind::WellFormed(_)
                     | ty::ClauseKind::ConstEvaluatable(_)
+                    | ty::ClauseKind::UnstableFeature(_)
                     | ty::ClauseKind::HostEffect(..) => {}
                 }
             }
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 301f5de9424..99a633e2b7d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -7,8 +7,7 @@ use smallvec::smallvec;
 
 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
 /// must be added to the struct header.
-pub(crate) type RequiredPredicates<'tcx> =
-    FxIndexMap<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, Span>;
+pub(crate) type RequiredPredicates<'tcx> = FxIndexMap<ty::ArgOutlivesPredicate<'tcx>, Span>;
 
 /// Given a requirement `T: 'a` or `'b: 'a`, deduce the
 /// outlives_component and add it to `required_predicates`
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 2c13c9ef438..bda02042aa6 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -735,8 +735,17 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span, cb);
             }
-            hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => {
+            hir::ItemKind::Trait(
+                constness,
+                is_auto,
+                safety,
+                ident,
+                generics,
+                bounds,
+                trait_items,
+            ) => {
                 let (cb, ib) = self.head("");
+                self.print_constness(constness);
                 self.print_is_auto(is_auto);
                 self.print_safety(safety);
                 self.word_nbsp("trait");
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 459c0498d50..a413f805873 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -161,16 +161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Resume type defaults to `()` if the coroutine has no argument.
                 let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
 
-                // In the new solver, we can just instantiate this eagerly
-                // with the witness. This will ensure that goals that don't need
-                // to stall on interior types will get processed eagerly.
-                let interior = if self.next_trait_solver() {
-                    Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args)
-                } else {
-                    self.next_ty_var(expr_span)
-                };
-
-                self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior));
+                let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args);
 
                 // Coroutines that come from coroutine closures have not yet determined
                 // their kind ty, so make a fresh infer var which will be constrained
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_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index af1fc045ac8..0b3d50ff219 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -625,50 +625,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // trigger query cycle ICEs, as doing so requires MIR.
         self.select_obligations_where_possible(|_| {});
 
-        let coroutines = std::mem::take(&mut *self.deferred_coroutine_interiors.borrow_mut());
-        debug!(?coroutines);
-
-        let mut obligations = vec![];
-
-        if !self.next_trait_solver() {
-            for &(coroutine_def_id, interior) in coroutines.iter() {
-                debug!(?coroutine_def_id);
-
-                // Create the `CoroutineWitness` type that we will unify with `interior`.
-                let args = ty::GenericArgs::identity_for_item(
-                    self.tcx,
-                    self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()),
-                );
-                let witness =
-                    Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args);
-
-                // Unify `interior` with `witness` and collect all the resulting obligations.
-                let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span;
-                let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
-                    span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
-                };
-                let ok = self
-                    .at(&self.misc(span), self.param_env)
-                    // Will never define opaque types, as all we do is instantiate a type variable.
-                    .eq(DefineOpaqueTypes::Yes, interior, witness)
-                    .expect("Failed to unify coroutine interior type");
-
-                obligations.extend(ok.obligations);
-            }
-        }
+        let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
+        else {
+            bug!();
+        };
 
-        if !coroutines.is_empty() {
-            obligations.extend(
+        if defining_opaque_types_and_generators
+            .iter()
+            .any(|def_id| self.tcx.is_coroutine(def_id.to_def_id()))
+        {
+            self.typeck_results.borrow_mut().coroutine_stalled_predicates.extend(
                 self.fulfillment_cx
                     .borrow_mut()
-                    .drain_stalled_obligations_for_coroutines(&self.infcx),
+                    .drain_stalled_obligations_for_coroutines(&self.infcx)
+                    .into_iter()
+                    .map(|o| (o.predicate, o.cause)),
             );
         }
-
-        self.typeck_results
-            .borrow_mut()
-            .coroutine_stalled_predicates
-            .extend(obligations.into_iter().map(|o| (o.predicate, o.cause)));
     }
 
     #[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index e4c62bf027b..367e2b6b372 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -54,6 +54,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
+            | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
             | ty::PredicateKind::Ambiguous => false,
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index 0037d5ac042..38413cca633 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -2,6 +2,7 @@ use std::fmt::Write;
 
 use hir::def_id::DefId;
 use hir::{HirId, ItemKind};
+use rustc_ast::join_path_idents;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
@@ -383,13 +384,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // All that is left is `_`! We need to use the full path. It doesn't matter which one we
         // pick, so just take the first one.
         match import_items[0].kind {
-            ItemKind::Use(path, _) => Some(
-                path.segments
-                    .iter()
-                    .map(|segment| segment.ident.to_string())
-                    .collect::<Vec<_>>()
-                    .join("::"),
-            ),
+            ItemKind::Use(path, _) => {
+                Some(join_path_idents(path.segments.iter().map(|seg| seg.ident)))
+            }
             _ => {
                 span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
             }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 94c93e73627..1f3969bd93c 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -921,6 +921,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::ClauseKind::ConstArgHasType(_, _)
                 | ty::ClauseKind::WellFormed(_)
                 | ty::ClauseKind::ConstEvaluatable(_)
+                | ty::ClauseKind::UnstableFeature(_)
                 | ty::ClauseKind::HostEffect(..) => None,
             }
         });
@@ -1649,7 +1650,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 }
             }
 
-            let sources = candidates.iter().map(|p| self.candidate_source(p, self_ty)).collect();
+            let sources =
+                applicable_candidates.iter().map(|p| self.candidate_source(p.0, self_ty)).collect();
             return Some(Err(MethodError::Ambiguity(sources)));
         }
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 2815621ffde..dbfa7e6273c 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1189,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         entry.1.insert((self_ty.span, ""));
                     }
                     Some(Node::Item(hir::Item {
-                        kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+                        kind: hir::ItemKind::Trait(_, rustc_ast::ast::IsAuto::Yes, ..),
                         span: item_span,
                         ..
                     })) => {
@@ -1201,7 +1201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Some(
                         Node::Item(hir::Item {
                             kind:
-                                hir::ItemKind::Trait(_, _, ident, ..)
+                                hir::ItemKind::Trait(_, _, _, ident, ..)
                                 | hir::ItemKind::TraitAlias(ident, ..),
                             ..
                         })
@@ -4084,7 +4084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             return;
                         }
                         Node::Item(hir::Item {
-                            kind: hir::ItemKind::Trait(_, _, ident, _, bounds, _),
+                            kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _),
                             ..
                         }) => {
                             let (sp, sep, article) = if bounds.is_empty() {
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 26be5fc6d19..9f4ab8ca5d4 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -63,8 +63,6 @@ pub(crate) struct TypeckRootCtxt<'tcx> {
 
     pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, HirId)>>,
 
-    pub(super) deferred_coroutine_interiors: RefCell<Vec<(LocalDefId, Ty<'tcx>)>>,
-
     pub(super) deferred_repeat_expr_checks:
         RefCell<Vec<(&'tcx hir::Expr<'tcx>, Ty<'tcx>, ty::Const<'tcx>)>>,
 
@@ -103,7 +101,6 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_transmute_checks: RefCell::new(Vec::new()),
             deferred_asm_checks: RefCell::new(Vec::new()),
-            deferred_coroutine_interiors: RefCell::new(Vec::new()),
             deferred_repeat_expr_checks: RefCell::new(Vec::new()),
             diverging_type_vars: RefCell::new(Default::default()),
             infer_var_info: RefCell::new(Default::default()),
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index d5d49e3188a..6be53c948c8 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -116,9 +116,15 @@ impl<'tcx> InferCtxt<'tcx> {
         }
 
         let region_obligations = self.take_registered_region_obligations();
+        let region_assumptions = self.take_registered_region_assumptions();
         debug!(?region_obligations);
         let region_constraints = self.with_region_constraints(|region_constraints| {
-            make_query_region_constraints(tcx, region_obligations, region_constraints)
+            make_query_region_constraints(
+                tcx,
+                region_obligations,
+                region_constraints,
+                region_assumptions,
+            )
         });
         debug!(?region_constraints);
 
@@ -169,6 +175,11 @@ impl<'tcx> InferCtxt<'tcx> {
             self.register_outlives_constraint(predicate, cause);
         }
 
+        for assumption in &query_response.value.region_constraints.assumptions {
+            let assumption = instantiate_value(self.tcx, &result_args, *assumption);
+            self.register_region_assumption(assumption);
+        }
+
         let user_result: R =
             query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
 
@@ -292,6 +303,18 @@ impl<'tcx> InferCtxt<'tcx> {
             }),
         );
 
+        // FIXME(higher_ranked_auto): Optimize this to instantiate all assumptions
+        // at once, rather than calling `instantiate_value` repeatedly which may
+        // create more universes.
+        output_query_region_constraints.assumptions.extend(
+            query_response
+                .value
+                .region_constraints
+                .assumptions
+                .iter()
+                .map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)),
+        );
+
         let user_result: R =
             query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
 
@@ -567,6 +590,7 @@ pub fn make_query_region_constraints<'tcx>(
     tcx: TyCtxt<'tcx>,
     outlives_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
     region_constraints: &RegionConstraintData<'tcx>,
+    assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
 ) -> QueryRegionConstraints<'tcx> {
     let RegionConstraintData { constraints, verifys } = region_constraints;
 
@@ -602,5 +626,5 @@ pub fn make_query_region_constraints<'tcx>(
         }))
         .collect();
 
-    QueryRegionConstraints { outlives }
+    QueryRegionConstraints { outlives, assumptions }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index cc3ad921489..2d269e320b6 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -149,6 +149,13 @@ pub struct InferCtxtInner<'tcx> {
     /// that all type inference variables have been bound and so forth.
     region_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
 
+    /// The outlives bounds that we assume must hold about placeholders that
+    /// come from instantiating the binder of coroutine-witnesses. These bounds
+    /// are deduced from the well-formedness of the witness's types, and are
+    /// necessary because of the way we anonymize the regions in a coroutine,
+    /// which may cause types to no longer be considered well-formed.
+    region_assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
+
     /// Caches for opaque type inference.
     opaque_type_storage: OpaqueTypeStorage<'tcx>,
 }
@@ -164,7 +171,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
             int_unification_storage: Default::default(),
             float_unification_storage: Default::default(),
             region_constraint_storage: Some(Default::default()),
-            region_obligations: vec![],
+            region_obligations: Default::default(),
+            region_assumptions: Default::default(),
             opaque_type_storage: Default::default(),
         }
     }
@@ -175,6 +183,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
+    pub fn region_assumptions(&self) -> &[ty::ArgOutlivesPredicate<'tcx>] {
+        &self.region_assumptions
+    }
+
+    #[inline]
     pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> {
         self.projection_cache.with_log(&mut self.undo_log)
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index cb5a33c5c97..47b738a4079 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
 use rustc_middle::{bug, ty};
 use tracing::debug;
@@ -39,6 +39,9 @@ pub struct OutlivesEnvironment<'tcx> {
     /// optimized in the future, though.
     region_bound_pairs: RegionBoundPairs<'tcx>,
     known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
+    /// Assumptions that come from the well-formedness of coroutines that we prove
+    /// auto trait bounds for during the type checking of this body.
+    higher_ranked_assumptions: FxHashSet<ty::ArgOutlivesPredicate<'tcx>>,
 }
 
 /// "Region-bound pairs" tracks outlives relations that are known to
@@ -52,6 +55,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
         extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
+        higher_ranked_assumptions: FxHashSet<ty::ArgOutlivesPredicate<'tcx>>,
     ) -> Self {
         let mut region_relation = TransitiveRelationBuilder::default();
         let mut region_bound_pairs = RegionBoundPairs::default();
@@ -88,6 +92,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
             known_type_outlives,
             free_region_map: FreeRegionMap { relation: region_relation.freeze() },
             region_bound_pairs,
+            higher_ranked_assumptions,
         }
     }
 
@@ -102,4 +107,8 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
     pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] {
         &self.known_type_outlives
     }
+
+    pub fn higher_ranked_assumptions(&self) -> &FxHashSet<ty::ArgOutlivesPredicate<'tcx>> {
+        &self.higher_ranked_assumptions
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 2a4544c1140..19911bfbd48 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -10,6 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog};
 use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
 use crate::infer::free_regions::RegionRelations;
 use crate::infer::lexical_region_resolve;
+use crate::infer::region_constraints::Constraint;
 
 pub mod env;
 pub mod for_liveness;
@@ -54,18 +55,29 @@ impl<'tcx> InferCtxt<'tcx> {
             }
         };
 
-        let storage = {
+        let mut storage = {
             let mut inner = self.inner.borrow_mut();
             let inner = &mut *inner;
             assert!(
                 self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
                 "region_obligations not empty: {:#?}",
-                inner.region_obligations
+                inner.region_obligations,
             );
             assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log));
             inner.region_constraint_storage.take().expect("regions already resolved")
         };
 
+        // Filter out any region-region outlives assumptions that are implied by
+        // coroutine well-formedness.
+        if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions {
+            storage.data.constraints.retain(|(constraint, _)| match *constraint {
+                Constraint::RegSubReg(r1, r2) => !outlives_env
+                    .higher_ranked_assumptions()
+                    .contains(&ty::OutlivesPredicate(r2.into(), r1)),
+                _ => true,
+            });
+        }
+
         let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
 
         let (lexical_region_resolutions, errors) =
@@ -93,6 +105,11 @@ impl<'tcx> InferCtxt<'tcx> {
             "region_obligations not empty: {:#?}",
             self.inner.borrow().region_obligations
         );
+        assert!(
+            self.inner.borrow().region_assumptions.is_empty(),
+            "region_assumptions not empty: {:#?}",
+            self.inner.borrow().region_assumptions
+        );
 
         self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 43504bd77c1..a8520c0e71d 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -84,7 +84,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
 impl<'tcx> InferCtxt<'tcx> {
     pub fn register_outlives_constraint(
         &self,
-        ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
+        ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>,
         cause: &ObligationCause<'tcx>,
     ) {
         match arg.kind() {
@@ -170,6 +170,16 @@ impl<'tcx> InferCtxt<'tcx> {
         std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
+    pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) {
+        let mut inner = self.inner.borrow_mut();
+        inner.undo_log.push(UndoLog::PushRegionAssumption);
+        inner.region_assumptions.push(assumption);
+    }
+
+    pub fn take_registered_region_assumptions(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> {
+        std::mem::take(&mut self.inner.borrow_mut().region_assumptions)
+    }
+
     /// Process the region obligations that must be proven (during
     /// `regionck`) for the given `body_id`, given information about
     /// the region bounds in scope and so forth.
@@ -220,6 +230,14 @@ impl<'tcx> InferCtxt<'tcx> {
                 let (sup_type, sub_region) =
                     (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self));
 
+                if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
+                    && outlives_env
+                        .higher_ranked_assumptions()
+                        .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region))
+                {
+                    continue;
+                }
+
                 debug!(?sup_type, ?sub_region, ?origin);
 
                 let outlives = &mut TypeOutlives::new(
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index 34e649afedc..40e4c329446 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -28,6 +28,7 @@ pub(crate) enum UndoLog<'tcx> {
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
     PushTypeOutlivesConstraint,
+    PushRegionAssumption,
 }
 
 macro_rules! impl_from {
@@ -77,6 +78,9 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
                 let popped = self.region_obligations.pop();
                 assert_matches!(popped, Some(_), "pushed region constraint but could not pop it");
             }
+            UndoLog::PushRegionAssumption => {
+                self.region_assumptions.pop();
+            }
         }
     }
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index a438cde018c..fb6897c7d89 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1055,17 +1055,11 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 });
             },
             {
-                sess.time("unused_lib_feature_checking", || {
-                    rustc_passes::stability::check_unused_or_stable_features(tcx)
-                });
-            },
-            {
                 // We force these queries to run,
                 // since they might not otherwise get called.
                 // This marks the corresponding crate-level attributes
                 // as used, and ensures that their values are valid.
                 tcx.ensure_ok().limits(());
-                tcx.ensure_ok().stability_index(());
             }
         );
     });
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 8d9f2385b71..1a1cfc9fa6f 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -440,6 +440,7 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly
     .help = only local labels of the form `<number>:` should be used in inline asm
     .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro
+
 lint_invalid_crate_type_value = invalid `crate_type` value
     .suggestion = did you mean
 
@@ -508,27 +509,50 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi
 
 lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
 
-lint_mismatched_lifetime_syntaxes =
-    lifetime flowing from input to output with different syntax can be confusing
-    .label_mismatched_lifetime_syntaxes_inputs =
-        {$n_inputs ->
-            [one] this lifetime flows
-            *[other] these lifetimes flow
-        } to the output
-    .label_mismatched_lifetime_syntaxes_outputs =
-        the {$n_outputs ->
-            [one] lifetime gets
-            *[other] lifetimes get
-        } resolved as `{$lifetime_name}`
+lint_mismatched_lifetime_syntaxes_eliding_while_named =
+    eliding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_help =
+    the same lifetime is referred to in inconsistent ways, making the signature confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named =
+    hiding or eliding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_while_elided =
+    hiding a lifetime that's elided elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_hiding_while_named =
+    hiding a lifetime that's named elsewhere is confusing
+
+lint_mismatched_lifetime_syntaxes_input_elided =
+    the lifetime is elided here
+
+lint_mismatched_lifetime_syntaxes_input_hidden =
+    the lifetime is hidden here
+
+lint_mismatched_lifetime_syntaxes_input_named =
+    the lifetime is named here
+
+lint_mismatched_lifetime_syntaxes_output_elided =
+    the same lifetime is elided here
+
+lint_mismatched_lifetime_syntaxes_output_hidden =
+    the same lifetime is hidden here
+
+lint_mismatched_lifetime_syntaxes_output_named =
+    the same lifetime is named here
 
 lint_mismatched_lifetime_syntaxes_suggestion_explicit =
-    one option is to consistently use `{$lifetime_name}`
+    consistently use `{$lifetime_name}`
 
 lint_mismatched_lifetime_syntaxes_suggestion_implicit =
-    one option is to consistently remove the lifetime
+    remove the lifetime name from references
 
 lint_mismatched_lifetime_syntaxes_suggestion_mixed =
-    one option is to remove the lifetime for references and use the anonymous lifetime for paths
+    remove the lifetime name from references and use `'_` for type paths
+
+lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths =
+    use `'_` for type paths
 
 lint_missing_unsafe_on_extern = extern blocks should be unsafe
     .suggestion = needs `unsafe` before the extern keyword
@@ -744,6 +768,9 @@ lint_redundant_semicolons_suggestion = remove {$multiple_semicolons ->
         *[false] this semicolon
     }
 
+lint_reexport_private_dependency =
+    {$kind} `{$name}` from private dependency '{$krate}' is re-exported
+
 lint_remove_mut_from_pattern = remove `mut` from the parameter
 
 lint_removed_lint = lint `{$name}` has been removed: {$reason}
@@ -790,6 +817,9 @@ lint_supertrait_as_deref_target = this `Deref` implementation is covered by an i
     .label2 = target type is a supertrait of `{$self_ty}`
     .help = consider removing this implementation or replacing it with a method instead
 
+lint_surrogate_char_cast = surrogate values are not valid for `char`
+    .note = `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values
+
 lint_suspicious_double_ref_clone =
     using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
 
@@ -799,6 +829,9 @@ lint_suspicious_double_ref_deref =
 lint_symbol_intern_string_literal = using `Symbol::intern` on a string literal
     .help = consider adding the symbol to `compiler/rustc_span/src/symbol.rs`
 
+lint_too_large_char_cast = value exceeds maximum `char` value
+    .note = maximum valid `char` value is `0x10FFFF`
+
 lint_trailing_semi_macro = trailing semicolon in macro used in expression position
     .note1 = macro invocations at the end of a block are treated as expressions
     .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 255ff56f62b..73e68834232 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1519,8 +1519,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     ClauseKind::TypeOutlives(..) |
                     ClauseKind::RegionOutlives(..) => "lifetime",
 
+                    ClauseKind::UnstableFeature(_)
                     // `ConstArgHasType` is never global as `ct` is always a param
-                    ClauseKind::ConstArgHasType(..)
+                    | ClauseKind::ConstArgHasType(..)
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
                     | ClauseKind::Projection(..)
@@ -1584,6 +1585,8 @@ impl EarlyLintPass for DoubleNegations {
         if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
             && let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
             && !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
+            // Don't lint if this jumps macro expansion boundary (Issue #143980)
+            && expr.span.eq_ctxt(inner.span)
         {
             cx.emit_span_lint(
                 DOUBLE_NEGATIONS,
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 653559009cc..f0fbf5bc81e 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -351,6 +351,9 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
+        BuiltinLintDiag::ReexportPrivateDependency { name, kind, krate } => {
+            lints::ReexportPrivateDependency { name, kind, krate }.decorate_lint(diag);
+        }
         BuiltinLintDiag::UnusedQualifications { removal_span } => {
             lints::UnusedQualifications { removal_span }.decorate_lint(diag);
         }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 419124d5144..f06757b3c23 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,7 +55,7 @@ mod invalid_from_utf8;
 mod late;
 mod let_underscore;
 mod levels;
-mod lifetime_syntax;
+pub mod lifetime_syntax;
 mod lints;
 mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 5465968e984..2a5a34cdc6e 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -140,43 +140,115 @@ fn report_mismatches<'tcx>(
     }
 }
 
-fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
-    // Categorize lifetimes into source/syntax buckets.
-    let mut n_hidden = 0;
-    let mut n_elided = 0;
-    let mut n_named = 0;
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum LifetimeSyntaxCategory {
+    Hidden,
+    Elided,
+    Named,
+}
 
-    for info in input_info.iter().chain(output_info) {
+impl LifetimeSyntaxCategory {
+    fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option<Self> {
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
-
         match syntax_source {
-            // Ignore any other kind of lifetime.
-            (_, Other) => continue,
-
             // E.g. `&T`.
-            (Implicit, Reference | OutlivesBound | PreciseCapturing) |
+            (Implicit, Reference) |
             // E.g. `&'_ T`.
-            (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitAnonymous, Reference) |
             // E.g. `ContainsLifetime<'_>`.
-            (ExplicitAnonymous, Path { .. }) => n_elided += 1,
+            (ExplicitAnonymous, Path { .. }) |
+            // E.g. `+ '_`, `+ use<'_>`.
+            (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Elided)
+            }
 
             // E.g. `ContainsLifetime`.
-            (Implicit, Path { .. }) => n_hidden += 1,
+            (Implicit, Path { .. }) => {
+                Some(Self::Hidden)
+            }
 
             // E.g. `&'a T`.
-            (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) |
+            (ExplicitBound, Reference) |
             // E.g. `ContainsLifetime<'a>`.
-            (ExplicitBound, Path { .. }) => n_named += 1,
-        };
+            (ExplicitBound, Path { .. }) |
+            // E.g. `+ 'a`, `+ use<'a>`.
+            (ExplicitBound, OutlivesBound | PreciseCapturing) => {
+                Some(Self::Named)
+            }
+
+            (Implicit, OutlivesBound | PreciseCapturing) |
+            (_, Other) => {
+                None
+            }
+        }
+    }
+}
+
+#[derive(Debug, Default)]
+pub struct LifetimeSyntaxCategories<T> {
+    pub hidden: T,
+    pub elided: T,
+    pub named: T,
+}
+
+impl<T> LifetimeSyntaxCategories<T> {
+    fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T {
+        use LifetimeSyntaxCategory::*;
+
+        match category {
+            Elided => &mut self.elided,
+            Hidden => &mut self.hidden,
+            Named => &mut self.named,
+        }
+    }
+}
+
+impl<T> LifetimeSyntaxCategories<Vec<T>> {
+    pub fn len(&self) -> LifetimeSyntaxCategories<usize> {
+        LifetimeSyntaxCategories {
+            hidden: self.hidden.len(),
+            elided: self.elided.len(),
+            named: self.named.len(),
+        }
+    }
+
+    pub fn flatten(&self) -> impl Iterator<Item = &T> {
+        let Self { hidden, elided, named } = self;
+        [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten()
+    }
+}
+
+impl std::ops::Add for LifetimeSyntaxCategories<usize> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        Self {
+            hidden: self.hidden + rhs.hidden,
+            elided: self.elided + rhs.elided,
+            named: self.named + rhs.named,
+        }
+    }
+}
+
+fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
+    let mut syntax_counts = LifetimeSyntaxCategories::<usize>::default();
+
+    for info in input_info.iter().chain(output_info) {
+        if let Some(category) = info.lifetime_syntax_category() {
+            *syntax_counts.select(category) += 1;
+        }
     }
 
-    let syntax_counts = (n_hidden, n_elided, n_named);
     tracing::debug!(?syntax_counts);
 
-    matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _))
+    matches!(
+        syntax_counts,
+        LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 }
+            | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ }
+    )
 }
 
 fn emit_mismatch_diagnostic<'tcx>(
@@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>(
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = (info.lifetime.syntax, info.lifetime.source);
+        let syntax_source = info.syntax_source();
 
         if let (_, Other) = syntax_source {
             // Ignore any other kind of lifetime.
@@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>(
             // E.g. `&'_ T`.
             (ExplicitAnonymous, Reference) => {
                 suggest_change_to_implicit.push(info);
-                suggest_change_to_mixed_implicit.push(info);
                 suggest_change_to_explicit_bound.push(info);
             }
 
@@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>(
         }
     }
 
+    let categorize = |infos: &[Info<'_>]| {
+        let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default();
+        for info in infos {
+            if let Some(category) = info.lifetime_syntax_category() {
+                categories.select(category).push(info.reporting_span());
+            }
+        }
+        categories
+    };
+
+    let inputs = categorize(input_info);
+    let outputs = categorize(output_info);
+
     let make_implicit_suggestions =
         |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
 
-    let inputs = input_info.iter().map(|info| info.reporting_span()).collect();
-    let outputs = output_info.iter().map(|info| info.reporting_span()).collect();
-
     let explicit_bound_suggestion = bound_lifetime.map(|info| {
         build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound)
     });
@@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>(
         ?explicit_anonymous_suggestion,
     );
 
-    let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned();
-
     // We can produce a number of suggestions which may overwhelm
     // the user. Instead, we order the suggestions based on Rust
     // idioms. The "best" choice is shown to the user and the
@@ -413,8 +492,8 @@ fn emit_mismatch_diagnostic<'tcx>(
 
     cx.emit_span_lint(
         MISMATCHED_LIFETIME_SYNTAXES,
-        Vec::clone(&inputs),
-        lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions },
+        inputs.flatten().copied().collect::<Vec<_>>(),
+        lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions },
     );
 }
 
@@ -422,12 +501,12 @@ fn build_mismatch_suggestion(
     lifetime_name: &str,
     infos: &[&Info<'_>],
 ) -> lints::MismatchedLifetimeSyntaxesSuggestion {
-    let lifetime_name_sugg = lifetime_name.to_owned();
+    let lifetime_name = lifetime_name.to_owned();
 
     let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect();
 
     lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
-        lifetime_name_sugg,
+        lifetime_name,
         suggestions,
         tool_only: false,
     }
@@ -441,6 +520,14 @@ struct Info<'tcx> {
 }
 
 impl<'tcx> Info<'tcx> {
+    fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) {
+        (self.lifetime.syntax, self.lifetime.source)
+    }
+
+    fn lifetime_syntax_category(&self) -> Option<LifetimeSyntaxCategory> {
+        LifetimeSyntaxCategory::new(self.syntax_source())
+    }
+
     fn lifetime_name(&self) -> &str {
         self.lifetime.ident.as_str()
     }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 21148833eaf..fd8d0f832aa 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -21,6 +21,7 @@ use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
 
 use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
 use crate::errors::{OverruledAttributeSub, RequestedLevel};
+use crate::lifetime_syntax::LifetimeSyntaxCategories;
 use crate::{LateContext, fluent_generated as fluent};
 
 // array_into_iter.rs
@@ -1747,6 +1748,20 @@ pub(crate) struct OverflowingLiteral<'a> {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_surrogate_char_cast)]
+#[note]
+pub(crate) struct SurrogateCharCast {
+    pub literal: u128,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_too_large_char_cast)]
+#[note]
+pub(crate) struct TooLargeCharCast {
+    pub literal: u128,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_uses_power_alignment)]
 pub(crate) struct UsesPowerAlignment;
 
@@ -3081,6 +3096,14 @@ pub(crate) struct HiddenGlobReexports {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_reexport_private_dependency)]
+pub(crate) struct ReexportPrivateDependency {
+    pub name: String,
+    pub kind: String,
+    pub krate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_unnecessary_qualification)]
 pub(crate) struct UnusedQualifications {
     #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
@@ -3194,31 +3217,60 @@ pub(crate) struct ReservedMultihash {
 
 #[derive(Debug)]
 pub(crate) struct MismatchedLifetimeSyntaxes {
-    pub lifetime_name: String,
-    pub inputs: Vec<Span>,
-    pub outputs: Vec<Span>,
+    pub inputs: LifetimeSyntaxCategories<Vec<Span>>,
+    pub outputs: LifetimeSyntaxCategories<Vec<Span>>,
 
     pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>,
 }
 
 impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes {
     fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
-        diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes);
+        let counts = self.inputs.len() + self.outputs.len();
+        let message = match counts {
+            LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => {
+                panic!("No lifetime mismatch detected")
+            }
 
-        diag.arg("lifetime_name", self.lifetime_name);
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named
+            }
+
+            LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named
+            }
+
+            LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => {
+                fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named
+            }
+        };
+        diag.primary_message(message);
 
-        diag.arg("n_inputs", self.inputs.len());
-        for input in self.inputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs);
-            diag.span_label(input, a);
+        for s in self.inputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden);
+        }
+        for s in self.inputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided);
+        }
+        for s in self.inputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named);
         }
 
-        diag.arg("n_outputs", self.outputs.len());
-        for output in self.outputs {
-            let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs);
-            diag.span_label(output, a);
+        for s in self.outputs.hidden {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden);
+        }
+        for s in self.outputs.elided {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided);
+        }
+        for s in self.outputs.named {
+            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named);
         }
 
+        diag.help(fluent::lint_mismatched_lifetime_syntaxes_help);
+
         let mut suggestions = self.suggestions.into_iter();
         if let Some(s) = suggestions.next() {
             diag.subdiagnostic(s);
@@ -3245,7 +3297,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion {
     },
 
     Explicit {
-        lifetime_name_sugg: String,
+        lifetime_name: String,
         suggestions: Vec<(Span, String)>,
         tool_only: bool,
     },
@@ -3285,6 +3337,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
             }
 
             Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => {
+                let message = if implicit_suggestions.is_empty() {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths
+                } else {
+                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed
+                };
+
                 let implicit_suggestions =
                     implicit_suggestions.into_iter().map(|s| (s, String::new()));
 
@@ -3292,19 +3350,19 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
                     implicit_suggestions.chain(explicit_anonymous_suggestions).collect();
 
                 diag.multipart_suggestion_with_style(
-                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed,
+                    message,
                     suggestions,
                     Applicability::MaybeIncorrect,
                     style(tool_only),
                 );
             }
 
-            Explicit { lifetime_name_sugg, suggestions, tool_only } => {
-                diag.arg("lifetime_name_sugg", lifetime_name_sugg);
+            Explicit { lifetime_name, suggestions, tool_only } => {
+                diag.arg("lifetime_name", lifetime_name);
                 let msg = diag.eagerly_translate(
                     fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit,
                 );
-                diag.remove_arg("lifetime_name_sugg");
+                diag.remove_arg("lifetime_name");
                 diag.multipart_suggestion_with_style(
                     msg,
                     suggestions,
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 3cc55eaa0f2..5513c703f1d 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
         let def_id = item.owner_id.to_def_id();
         // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
         // the latter will report `where_clause_object_safety` lint.
-        if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind
+        if let hir::ItemKind::Trait(_, _, _, ident, ..) = item.kind
             && cx.tcx.is_dyn_compatible(def_id)
         {
             let direct_super_traits_iter = cx
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 826bce2c315..b2fa0fba76d 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -160,12 +160,10 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
                 let (arg_indices, are_zsts_allowed): (&[_], _) = match diag_name {
                     sym::ptr_read
                     | sym::ptr_read_unaligned
-                    | sym::ptr_read_volatile
                     | sym::ptr_replace
                     | sym::ptr_write
                     | sym::ptr_write_bytes
-                    | sym::ptr_write_unaligned
-                    | sym::ptr_write_volatile => (&[0], true),
+                    | sym::ptr_write_unaligned => (&[0], true),
                     sym::slice_from_raw_parts | sym::slice_from_raw_parts_mut => (&[0], false),
                     sym::ptr_copy
                     | sym::ptr_copy_nonoverlapping
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index d44f45177bd..2bac58ba23d 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -12,7 +12,7 @@ use crate::context::LintContext;
 use crate::lints::{
     OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
     OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
-    RangeEndpointOutOfRange, UseInclusiveRange,
+    RangeEndpointOutOfRange, SurrogateCharCast, TooLargeCharCast, UseInclusiveRange,
 };
 use crate::types::{OVERFLOWING_LITERALS, TypeLimits};
 
@@ -38,12 +38,18 @@ fn lint_overflowing_range_endpoint<'tcx>(
 
     // We only want to handle exclusive (`..`) ranges,
     // which are represented as `ExprKind::Struct`.
-    let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false };
-    let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
+    let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else {
+        return false;
+    };
+    let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else {
+        return false;
+    };
     if !is_range_literal(struct_expr) {
         return false;
     };
-    let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false };
+    let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else {
+        return false;
+    };
 
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
@@ -61,7 +67,9 @@ fn lint_overflowing_range_endpoint<'tcx>(
     };
 
     let sub_sugg = if span.lo() == lit_span.lo() {
-        let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
+        let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else {
+            return false;
+        };
         UseInclusiveRange::WithoutParen {
             sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
             start,
@@ -316,11 +324,25 @@ fn lint_uint_literal<'tcx>(
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
-                        cx.emit_span_lint(
-                            OVERFLOWING_LITERALS,
-                            par_e.span,
-                            OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
-                        );
+                        if lit_val > 0x10FFFF {
+                            cx.emit_span_lint(
+                                OVERFLOWING_LITERALS,
+                                par_e.span,
+                                TooLargeCharCast { literal: lit_val },
+                            );
+                        } else if (0xD800..=0xDFFF).contains(&lit_val) {
+                            cx.emit_span_lint(
+                                OVERFLOWING_LITERALS,
+                                par_e.span,
+                                SurrogateCharCast { literal: lit_val },
+                            );
+                        } else {
+                            cx.emit_span_lint(
+                                OVERFLOWING_LITERALS,
+                                par_e.span,
+                                OnlyCastu8ToChar { span: par_e.span, literal: lit_val },
+                            );
+                        }
                         return;
                     }
                 }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index cd402c9234f..fe068d96b74 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -739,6 +739,11 @@ pub enum BuiltinLintDiag {
         /// The local binding that shadows the glob reexport.
         private_item_span: Span,
     },
+    ReexportPrivateDependency {
+        name: String,
+        kind: String,
+        krate: Symbol,
+    },
     UnusedQualifications {
         /// The span of the unnecessarily-qualified path to remove.
         removal_span: Span,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index cc33764e485..a2e4d7306cb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -396,7 +396,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
     const char *SplitDwarfFile, const char *OutputObjFile,
     const char *DebugInfoCompression, bool UseEmulatedTls,
-    const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
+    const char *ArgsCstrBuff, size_t ArgsCstrBuffLen, bool UseWasmEH) {
 
   auto OptLevel = fromRust(RustOptLevel);
   auto RM = fromRust(RustReloc);
@@ -462,6 +462,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     Options.ThreadModel = ThreadModel::Single;
   }
 
+  if (UseWasmEH)
+    Options.ExceptionModel = ExceptionHandling::Wasm;
+
   Options.EmitStackSizeSection = EmitStackSizeSection;
 
   if (ArgsCstrBuff != nullptr) {
@@ -700,6 +703,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 +1076,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_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index b50453cb0df..5cd98038fc6 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1131,7 +1131,7 @@ fn should_encode_mir(
                     && reachable_set.contains(&def_id)
                     && (generics.requires_monomorphization(tcx)
                         || tcx.cross_crate_inlinable(def_id)));
-            // The function has a `const` modifier or is in a `#[const_trait]`.
+            // The function has a `const` modifier or is in a `const trait`.
             let is_const_fn = tcx.is_const_fn(def_id.to_def_id())
                 || tcx.is_const_default_method(def_id.to_def_id());
             (is_const_fn, opt)
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index 84710e5e636..42a1e7377f4 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -940,7 +940,7 @@ impl<'tcx> TyCtxt<'tcx> {
             }) => until_within(*outer_span, ty.span),
             // With generics and bounds.
             Node::Item(Item {
-                kind: ItemKind::Trait(_, _, _, generics, bounds, _),
+                kind: ItemKind::Trait(_, _, _, _, generics, bounds, _),
                 span: outer_span,
                 ..
             })
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 2bbc48b633c..4fe4c2dadee 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -81,13 +81,18 @@ pub struct QueryResponse<'tcx, R> {
 #[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct QueryRegionConstraints<'tcx> {
     pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
+    pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
 }
 
 impl QueryRegionConstraints<'_> {
-    /// Represents an empty (trivially true) set of region
-    /// constraints.
+    /// Represents an empty (trivially true) set of region constraints.
+    ///
+    /// FIXME(higher_ranked_auto): This could still just be true if there are only assumptions?
+    /// Because I don't expect for us to get cases where an assumption from one query would
+    /// discharge a requirement from another query, which is a potential problem if we did throw
+    /// away these assumptions because there were no constraints.
     pub fn is_empty(&self) -> bool {
-        self.outlives.is_empty()
+        self.outlives.is_empty() && self.assumptions.is_empty()
     }
 }
 
@@ -130,8 +135,7 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
     }
 }
 
-pub type QueryOutlivesConstraint<'tcx> =
-    (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>);
+pub type QueryOutlivesConstraint<'tcx> = (ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>);
 
 #[derive(Default)]
 pub struct CanonicalParamEnvCache<'tcx> {
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 2f16d385efb..6eae3b51e29 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use rustc_abi::Align;
 use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs;
 use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr};
@@ -6,6 +8,26 @@ use rustc_span::Symbol;
 use rustc_target::spec::SanitizerSet;
 
 use crate::mir::mono::Linkage;
+use crate::ty::{InstanceKind, TyCtxt};
+
+impl<'tcx> TyCtxt<'tcx> {
+    pub fn codegen_instance_attrs(
+        self,
+        instance_kind: InstanceKind<'_>,
+    ) -> Cow<'tcx, CodegenFnAttrs> {
+        let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id()));
+
+        // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that
+        // are generated for indirect function calls.
+        if !matches!(instance_kind, InstanceKind::Item(_)) {
+            if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+                attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED);
+            }
+        }
+
+        attrs
+    }
+}
 
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
 pub struct CodegenFnAttrs {
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 99faba7b2c0..dc9311188e8 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -7,10 +7,9 @@ use rustc_ast::NodeId;
 use rustc_attr_data_structures::{
     self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
 };
-use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee};
 use rustc_feature::GateIssue;
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, HirId};
 use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic};
 use rustc_session::Session;
@@ -65,48 +64,6 @@ impl DeprecationEntry {
     }
 }
 
-/// A stability index, giving the stability level for items and methods.
-#[derive(HashStable, Debug)]
-pub struct Index {
-    /// This is mostly a cache, except the stabilities of local items
-    /// are filled by the annotator.
-    pub stab_map: LocalDefIdMap<Stability>,
-    pub const_stab_map: LocalDefIdMap<ConstStability>,
-    pub default_body_stab_map: LocalDefIdMap<DefaultBodyStability>,
-    pub depr_map: LocalDefIdMap<DeprecationEntry>,
-    /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
-    /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
-    /// exists, then this map will have a `impliee -> implier` entry.
-    ///
-    /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
-    /// specify their implications (both `implies` and `implied_by`). If only one of the two
-    /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
-    /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
-    /// reported, only the `#[stable]` attribute information is available, so the map is necessary
-    /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
-    /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
-    /// unstable feature" error for a feature that was implied.
-    pub implications: UnordMap<Symbol, Symbol>,
-}
-
-impl Index {
-    pub fn local_stability(&self, def_id: LocalDefId) -> Option<Stability> {
-        self.stab_map.get(&def_id).copied()
-    }
-
-    pub fn local_const_stability(&self, def_id: LocalDefId) -> Option<ConstStability> {
-        self.const_stab_map.get(&def_id).copied()
-    }
-
-    pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
-        self.default_body_stab_map.get(&def_id).copied()
-    }
-
-    pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
-        self.depr_map.get(&def_id).cloned()
-    }
-}
-
 pub fn report_unstable(
     sess: &Session,
     feature: Symbol,
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_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 71e0c943fbb..3e68afbfabd 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> {
 /// Details of why a pointer had to be in-bounds.
 #[derive(Debug, Copy, Clone)]
 pub enum CheckInAllocMsg {
-    /// We are access memory.
+    /// We are accessing memory.
     MemoryAccess,
     /// We are doing pointer arithmetic.
     InboundsPointerArithmetic,
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 47ba850d50d..2d7ddd105bd 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -152,7 +152,7 @@ impl<'tcx> MonoItem<'tcx> {
         // If the function is #[naked] or contains any other attribute that requires exactly-once
         // instantiation:
         // We emit an unused_attributes lint for this case, which should be kept in sync if possible.
-        let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
+        let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def);
         if codegen_fn_attrs.contains_extern_indicator()
             || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
         {
@@ -219,7 +219,7 @@ impl<'tcx> MonoItem<'tcx> {
         // functions the same as those that unconditionally get LocalCopy codegen. It's only when
         // we get here that we can at least not codegen a #[inline(never)] generic function in all
         // of our CGUs.
-        if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
+        if let InlineAttr::Never = codegen_fn_attrs.inline
             && self.is_generic_fn()
         {
             return InstantiationMode::GloballyShared { may_conflict: true };
@@ -234,14 +234,13 @@ impl<'tcx> MonoItem<'tcx> {
     }
 
     pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option<Linkage> {
-        let def_id = match *self {
-            MonoItem::Fn(ref instance) => instance.def_id(),
-            MonoItem::Static(def_id) => def_id,
+        let instance_kind = match *self {
+            MonoItem::Fn(ref instance) => instance.def,
+            MonoItem::Static(def_id) => InstanceKind::Item(def_id),
             MonoItem::GlobalAsm(..) => return None,
         };
 
-        let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
-        codegen_fn_attrs.linkage
+        tcx.codegen_instance_attrs(instance_kind).linkage
     }
 
     /// Returns `true` if this instance is instantiable - whether it has no unsatisfied
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 935cc889574..ae8c8259be4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -112,7 +112,7 @@ use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::EffectiveVisibilities;
 use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
-use crate::middle::stability::{self, DeprecationEntry};
+use crate::middle::stability::DeprecationEntry;
 use crate::mir::interpret::{
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
     EvalToValTreeResult, GlobalId, LitToConstInput,
@@ -988,7 +988,7 @@ rustc_queries! {
     }
 
     query coroutine_hidden_types(
-        def_id: DefId
+        def_id: DefId,
     ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
         desc { "looking up the hidden types stored across await points in a coroutine" }
     }
@@ -1505,6 +1505,15 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    /// Returns the `CodegenFnAttrs` for the item at `def_id`.
+    ///
+    /// If possible, use `tcx.codegen_instance_attrs` instead. That function takes the
+    /// instance kind into account.
+    ///
+    /// For example, the `#[naked]` attribute should be applied for `InstanceKind::Item`,
+    /// but should not be applied if the instance kind is `InstanceKind::ReifyShim`.
+    /// Using this query would include the attribute regardless of the actual instance
+    /// kind at the call site.
     query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs {
         desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
         arena_cache
@@ -2162,6 +2171,18 @@ rustc_queries! {
         separate_provide_extern
         arena_cache
     }
+    /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
+    /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
+    /// exists, then this map will have a `impliee -> implier` entry.
+    ///
+    /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
+    /// specify their implications (both `implies` and `implied_by`). If only one of the two
+    /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
+    /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
+    /// reported, only the `#[stable]` attribute information is available, so the map is necessary
+    /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
+    /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
+    /// unstable feature" error for a feature that was implied.
     query stability_implications(_: CrateNum) -> &'tcx UnordMap<Symbol, Symbol> {
         arena_cache
         desc { "calculating the implications between `#[unstable]` features defined in a crate" }
@@ -2268,11 +2289,6 @@ rustc_queries! {
         desc { "fetching potentially unused trait imports" }
     }
 
-    query stability_index(_: ()) -> &'tcx stability::Index {
-        arena_cache
-        eval_always
-        desc { "calculating the stability index for the local crate" }
-    }
     /// All available crates in the graph, including those that should not be user-facing
     /// (such as private crates).
     query crates(_: ()) -> &'tcx [CrateNum] {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 98b2ce01d89..7e6bcfee025 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -65,7 +65,7 @@ use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, Canonica
 use crate::lint::lint_level;
 use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
-use crate::middle::{resolve_bound_vars, stability};
+use crate::middle::resolve_bound_vars;
 use crate::mir::interpret::{self, Allocation, ConstAllocation};
 use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
 use crate::query::plumbing::QuerySystem;
@@ -137,6 +137,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type FnInputTys = &'tcx [Ty<'tcx>];
     type ParamTy = ParamTy;
     type BoundTy = ty::BoundTy;
+    type Symbol = Symbol;
 
     type PlaceholderTy = ty::PlaceholderType;
     type ErrorGuaranteed = ErrorGuaranteed;
@@ -162,6 +163,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type BoundRegion = ty::BoundRegion;
     type PlaceholderRegion = ty::PlaceholderRegion;
 
+    type RegionAssumptions = &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>>;
+
     type ParamEnv = ty::ParamEnv<'tcx>;
     type Predicate = Predicate<'tcx>;
 
@@ -713,17 +716,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self,
         defining_anchor: Self::LocalDefId,
     ) -> Self::LocalDefIds {
-        if self.next_trait_solver_globally() {
-            let coroutines_defined_by = self
-                .nested_bodies_within(defining_anchor)
-                .iter()
-                .filter(|def_id| self.is_coroutine(def_id.to_def_id()));
-            self.mk_local_def_ids_from_iter(
-                self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by),
-            )
-        } else {
-            self.opaque_types_defined_by(defining_anchor)
-        }
+        let coroutines_defined_by = self
+            .nested_bodies_within(defining_anchor)
+            .iter()
+            .filter(|def_id| self.is_coroutine(def_id.to_def_id()));
+        self.mk_local_def_ids_from_iter(
+            self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by),
+        )
     }
 }
 
@@ -833,6 +832,13 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
     fn associated_const_equality(self) -> bool {
         self.associated_const_equality()
     }
+
+    fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool {
+        // We don't consider feature bounds to hold in the crate when `staged_api` feature is
+        // enabled, even if it is enabled through `#[feature]`.
+        // This is to prevent accidentally leaking unstable APIs to stable.
+        !self.staged_api() && self.enabled(symbol)
+    }
 }
 
 impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {
@@ -874,6 +880,7 @@ pub struct CtxtInterners<'tcx> {
     offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
     valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>,
     patterns: InternedSet<'tcx, List<ty::Pattern<'tcx>>>,
+    outlives: InternedSet<'tcx, List<ty::ArgOutlivesPredicate<'tcx>>>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -911,6 +918,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             offset_of: InternedSet::with_capacity(N),
             valtree: InternedSet::with_capacity(N),
             patterns: InternedSet::with_capacity(N),
+            outlives: InternedSet::with_capacity(N),
         }
     }
 
@@ -1799,10 +1807,6 @@ impl<'tcx> TyCtxt<'tcx> {
         )
     }
 
-    pub fn stability(self) -> &'tcx stability::Index {
-        self.stability_index(())
-    }
-
     pub fn features(self) -> &'tcx rustc_feature::Features {
         self.features_query(())
     }
@@ -2692,6 +2696,7 @@ slice_interners!(
     captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>),
     offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
     patterns: pub mk_patterns(Pattern<'tcx>),
+    outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>),
 );
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -3107,6 +3112,17 @@ impl<'tcx> TyCtxt<'tcx> {
         T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs))
     }
 
+    pub fn mk_outlives_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: CollectAndApply<
+                ty::ArgOutlivesPredicate<'tcx>,
+                &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>>,
+            >,
+    {
+        T::collect_and_apply(iter, |xs| self.mk_outlives(xs))
+    }
+
     /// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`,
     /// typically generated by `#[derive(LintDiagnostic)]`).
     #[track_caller]
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6e8f1e8fdd5..a7cde2ad485 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -88,7 +88,7 @@ pub use self::opaque_types::OpaqueTypeKey;
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::pattern::{Pattern, PatternKind};
 pub use self::predicate::{
-    AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
+    AliasTerm, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
     ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef,
     HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
     PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index bc2ac42b6b1..46f254e9d30 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -26,6 +26,7 @@ pub type SubtypePredicate<'tcx> = ir::SubtypePredicate<TyCtxt<'tcx>>;
 pub type OutlivesPredicate<'tcx, T> = ir::OutlivesPredicate<TyCtxt<'tcx>, T>;
 pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::Region<'tcx>>;
 pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, Ty<'tcx>>;
+pub type ArgOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>;
 pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
 pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
 pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
@@ -131,6 +132,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(ClauseKind::TypeOutlives(_))
             | PredicateKind::Clause(ClauseKind::Projection(_))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
+            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
             | PredicateKind::DynCompatible(_)
             | PredicateKind::Subtype(_)
             | PredicateKind::Coerce(_)
@@ -649,6 +651,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(ClauseKind::Projection(..))
             | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
+            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
             | PredicateKind::NormalizesTo(..)
             | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
@@ -670,6 +673,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(ClauseKind::Trait(..))
             | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
+            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
             | PredicateKind::NormalizesTo(..)
             | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8f0f9b21dc1..9ee64df0ad0 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1210,30 +1210,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     }
 
                     for (assoc_item_def_id, term) in assoc_items {
-                        // Skip printing `<{coroutine@} as Coroutine<_>>::Return` from async blocks,
-                        // unless we can find out what coroutine return type it comes from.
-                        let term = if let Some(ty) = term.skip_binder().as_type()
-                            && let ty::Alias(ty::Projection, proj) = ty.kind()
-                            && let Some(assoc) = tcx.opt_associated_item(proj.def_id)
-                            && assoc
-                                .trait_container(tcx)
-                                .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
-                            && assoc.opt_name() == Some(rustc_span::sym::Return)
-                        {
-                            if let ty::Coroutine(_, args) = args.type_at(0).kind() {
-                                let return_ty = args.as_coroutine().return_ty();
-                                if !return_ty.is_ty_var() {
-                                    return_ty.into()
-                                } else {
-                                    continue;
-                                }
-                            } else {
-                                continue;
-                            }
-                        } else {
-                            term.skip_binder()
-                        };
-
                         if first {
                             p!("<");
                             first = false;
@@ -1243,7 +1219,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
                         p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name()));
 
-                        match term.kind() {
+                        match term.skip_binder().kind() {
                             TermKind::Ty(ty) => p!(print(ty)),
                             TermKind::Const(c) => p!(print(c)),
                         };
@@ -2430,7 +2406,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
         }
 
         let verbose = self.should_print_verbose();
-        disambiguated_data.fmt_maybe_verbose(self, verbose)?;
+        write!(self, "{}", disambiguated_data.as_sym(verbose))?;
 
         self.empty_path = false;
 
@@ -3237,6 +3213,7 @@ define_print! {
             ty::ClauseKind::ConstEvaluatable(ct) => {
                 p!("the constant `", print(ct), "` can be evaluated")
             }
+            ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index af9c98bd87d..ab31d943408 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -802,4 +802,5 @@ list_fold! {
     &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> : mk_poly_existential_predicates,
     &'tcx ty::List<PlaceElem<'tcx>> : mk_place_elems,
     &'tcx ty::List<ty::Pattern<'tcx>> : mk_patterns,
+    &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>> : mk_outlives,
 }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index ea25ce65f77..59e2b2a034d 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -20,7 +20,7 @@ pub struct TraitDef {
 
     pub safety: hir::Safety,
 
-    /// Whether this trait has been annotated with `#[const_trait]`.
+    /// Whether this trait is `const`.
     pub constness: hir::Constness,
 
     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index ccf76dc7108..986c001de5e 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,3 +1,4 @@
+use rustc_attr_data_structures::{AttributeKind, CoverageStatus, find_attr};
 use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind};
@@ -5,7 +6,6 @@ use rustc_middle::mir::{Body, Statement, StatementKind};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::sym;
 use tracing::trace;
 
 use crate::coverage::counters::node_flow::make_node_counters;
@@ -58,26 +58,20 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 /// Query implementation for `coverage_attr_on`.
 fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     // Check for annotations directly on this def.
-    if let Some(attr) = tcx.get_attr(def_id, sym::coverage) {
-        match attr.meta_item_list().as_deref() {
-            Some([item]) if item.has_name(sym::off) => return false,
-            Some([item]) if item.has_name(sym::on) => return true,
-            Some(_) | None => {
-                // Other possibilities should have been rejected by `rustc_parse::validate_attr`.
-                // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880).
-                tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute");
-            }
+    if let Some(coverage_status) =
+        find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status)
+    {
+        *coverage_status == CoverageStatus::On
+    } else {
+        match tcx.opt_local_parent(def_id) {
+            // Check the parent def (and so on recursively) until we find an
+            // enclosing attribute or reach the crate root.
+            Some(parent) => tcx.coverage_attr_on(parent),
+            // We reached the crate root without seeing a coverage attribute, so
+            // allow coverage instrumentation by default.
+            None => true,
         }
     }
-
-    match tcx.opt_local_parent(def_id) {
-        // Check the parent def (and so on recursively) until we find an
-        // enclosing attribute or reach the crate root.
-        Some(parent) => tcx.coverage_attr_on(parent),
-        // We reached the crate root without seeing a coverage attribute, so
-        // allow coverage instrumentation by default.
-        None => true,
-    }
 }
 
 /// Query implementation for `coverage_ids_info`.
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 6b11706d2b5..6657f89ceb5 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -105,7 +105,6 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
-use rustc_span::def_id::DefId;
 use smallvec::SmallVec;
 use tracing::{debug, instrument, trace};
 
@@ -130,7 +129,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
         let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);
 
         for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) {
-            let opaque = state.new_opaque();
+            let opaque = state.new_opaque(body.local_decls[local].ty);
             state.assign(local, opaque);
         }
 
@@ -155,22 +154,6 @@ newtype_index! {
     struct VnIndex {}
 }
 
-/// Computing the aggregate's type can be quite slow, so we only keep the minimal amount of
-/// information to reconstruct it when needed.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-enum AggregateTy<'tcx> {
-    /// Invariant: this must not be used for an empty array.
-    Array,
-    Tuple,
-    Def(DefId, ty::GenericArgsRef<'tcx>),
-    RawPtr {
-        /// Needed for cast propagation.
-        data_pointer_ty: Ty<'tcx>,
-        /// The data pointer can be anything thin, so doesn't determine the output.
-        output_pointer_ty: Ty<'tcx>,
-    },
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 enum AddressKind {
     Ref(BorrowKind),
@@ -193,7 +176,14 @@ enum Value<'tcx> {
     },
     /// An aggregate value, either tuple/closure/struct/enum.
     /// This does not contain unions, as we cannot reason with the value.
-    Aggregate(AggregateTy<'tcx>, VariantIdx, Vec<VnIndex>),
+    Aggregate(VariantIdx, Vec<VnIndex>),
+    /// A raw pointer aggregate built from a thin pointer and metadata.
+    RawPtr {
+        /// Thin pointer component. This is field 0 in MIR.
+        pointer: VnIndex,
+        /// Metadata component. This is field 1 in MIR.
+        metadata: VnIndex,
+    },
     /// This corresponds to a `[value; count]` expression.
     Repeat(VnIndex, ty::Const<'tcx>),
     /// The address of a place.
@@ -206,7 +196,7 @@ enum Value<'tcx> {
 
     // Extractions.
     /// This is the *value* obtained by projecting another value.
-    Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>),
+    Projection(VnIndex, ProjectionElem<VnIndex, ()>),
     /// Discriminant of the given value.
     Discriminant(VnIndex),
     /// Length of an array or slice.
@@ -219,8 +209,6 @@ enum Value<'tcx> {
     Cast {
         kind: CastKind,
         value: VnIndex,
-        from: Ty<'tcx>,
-        to: Ty<'tcx>,
     },
 }
 
@@ -228,12 +216,13 @@ struct VnState<'body, 'tcx> {
     tcx: TyCtxt<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
     local_decls: &'body LocalDecls<'tcx>,
+    is_coroutine: bool,
     /// Value stored in each local.
     locals: IndexVec<Local, Option<VnIndex>>,
     /// Locals that are assigned that value.
     // This vector does not hold all the values of `VnIndex` that we create.
     rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
-    values: FxIndexSet<Value<'tcx>>,
+    values: FxIndexSet<(Value<'tcx>, Ty<'tcx>)>,
     /// Values evaluated as constants if possible.
     evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
     /// Counter to generate different values.
@@ -265,6 +254,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             tcx,
             ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
             local_decls,
+            is_coroutine: body.coroutine.is_some(),
             locals: IndexVec::from_elem(None, local_decls),
             rev_locals: IndexVec::with_capacity(num_values),
             values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
@@ -282,8 +272,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     }
 
     #[instrument(level = "trace", skip(self), ret)]
-    fn insert(&mut self, value: Value<'tcx>) -> VnIndex {
-        let (index, new) = self.values.insert_full(value);
+    fn insert(&mut self, ty: Ty<'tcx>, value: Value<'tcx>) -> VnIndex {
+        let (index, new) = self.values.insert_full((value, ty));
         let index = VnIndex::from_usize(index);
         if new {
             // Grow `evaluated` and `rev_locals` here to amortize the allocations.
@@ -305,20 +295,33 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     /// Create a new `Value` for which we have no information at all, except that it is distinct
     /// from all the others.
     #[instrument(level = "trace", skip(self), ret)]
-    fn new_opaque(&mut self) -> VnIndex {
+    fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex {
         let value = Value::Opaque(self.next_opaque());
-        self.insert(value)
+        self.insert(ty, value)
     }
 
     /// Create a new `Value::Address` distinct from all the others.
     #[instrument(level = "trace", skip(self), ret)]
     fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex {
+        let pty = place.ty(self.local_decls, self.tcx).ty;
+        let ty = match kind {
+            AddressKind::Ref(bk) => {
+                Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, pty, bk.to_mutbl_lossy())
+            }
+            AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, pty, mutbl.to_mutbl_lossy()),
+        };
         let value = Value::Address { place, kind, provenance: self.next_opaque() };
-        self.insert(value)
+        self.insert(ty, value)
     }
 
+    #[inline]
     fn get(&self, index: VnIndex) -> &Value<'tcx> {
-        self.values.get_index(index.as_usize()).unwrap()
+        &self.values.get_index(index.as_usize()).unwrap().0
+    }
+
+    #[inline]
+    fn ty(&self, index: VnIndex) -> Ty<'tcx> {
+        self.values.get_index(index.as_usize()).unwrap().1
     }
 
     /// Record that `local` is assigned `value`. `local` must be SSA.
@@ -341,29 +344,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             debug_assert_ne!(disambiguator, 0);
             disambiguator
         };
-        self.insert(Value::Constant { value, disambiguator })
+        self.insert(value.ty(), Value::Constant { value, disambiguator })
     }
 
     fn insert_bool(&mut self, flag: bool) -> VnIndex {
         // Booleans are deterministic.
         let value = Const::from_bool(self.tcx, flag);
         debug_assert!(value.is_deterministic());
-        self.insert(Value::Constant { value, disambiguator: 0 })
+        self.insert(self.tcx.types.bool, Value::Constant { value, disambiguator: 0 })
     }
 
-    fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
+    fn insert_scalar(&mut self, ty: Ty<'tcx>, scalar: Scalar) -> VnIndex {
         // Scalars are deterministic.
         let value = Const::from_scalar(self.tcx, scalar, ty);
         debug_assert!(value.is_deterministic());
-        self.insert(Value::Constant { value, disambiguator: 0 })
+        self.insert(ty, Value::Constant { value, disambiguator: 0 })
     }
 
-    fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
-        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values))
+    fn insert_tuple(&mut self, ty: Ty<'tcx>, values: Vec<VnIndex>) -> VnIndex {
+        self.insert(ty, Value::Aggregate(VariantIdx::ZERO, values))
     }
 
-    fn insert_deref(&mut self, value: VnIndex) -> VnIndex {
-        let value = self.insert(Value::Projection(value, ProjectionElem::Deref));
+    fn insert_deref(&mut self, ty: Ty<'tcx>, value: VnIndex) -> VnIndex {
+        let value = self.insert(ty, Value::Projection(value, ProjectionElem::Deref));
         self.derefs.push(value);
         value
     }
@@ -371,14 +374,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     fn invalidate_derefs(&mut self) {
         for deref in std::mem::take(&mut self.derefs) {
             let opaque = self.next_opaque();
-            *self.values.get_index_mut2(deref.index()).unwrap() = Value::Opaque(opaque);
+            self.values.get_index_mut2(deref.index()).unwrap().0 = Value::Opaque(opaque);
         }
     }
 
     #[instrument(level = "trace", skip(self), ret)]
     fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
         use Value::*;
+        let ty = self.ty(value);
+        // Avoid computing layouts inside a coroutine, as that can cause cycles.
+        let ty = if !self.is_coroutine || ty.is_scalar() {
+            self.ecx.layout_of(ty).ok()?
+        } else {
+            return None;
+        };
         let op = match *self.get(value) {
+            _ if ty.is_zst() => ImmTy::uninit(ty).into(),
+
             Opaque(_) => return None,
             // Do not bother evaluating repeat expressions. This would uselessly consume memory.
             Repeat(..) => return None,
@@ -386,42 +398,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             Constant { ref value, disambiguator: _ } => {
                 self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()?
             }
-            Aggregate(kind, variant, ref fields) => {
+            Aggregate(variant, ref fields) => {
                 let fields = fields
                     .iter()
                     .map(|&f| self.evaluated[f].as_ref())
                     .collect::<Option<Vec<_>>>()?;
-                let ty = match kind {
-                    AggregateTy::Array => {
-                        assert!(fields.len() > 0);
-                        Ty::new_array(self.tcx, fields[0].layout.ty, fields.len() as u64)
-                    }
-                    AggregateTy::Tuple => {
-                        Ty::new_tup_from_iter(self.tcx, fields.iter().map(|f| f.layout.ty))
-                    }
-                    AggregateTy::Def(def_id, args) => {
-                        self.tcx.type_of(def_id).instantiate(self.tcx, args)
-                    }
-                    AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty,
-                };
-                let variant = if ty.is_enum() { Some(variant) } else { None };
-                let ty = self.ecx.layout_of(ty).ok()?;
-                if ty.is_zst() {
-                    ImmTy::uninit(ty).into()
-                } else if matches!(kind, AggregateTy::RawPtr { .. }) {
-                    // Pointers don't have fields, so don't `project_field` them.
-                    let data = self.ecx.read_pointer(fields[0]).discard_err()?;
-                    let meta = if fields[1].layout.is_zst() {
-                        MemPlaceMeta::None
-                    } else {
-                        MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?)
-                    };
-                    let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
-                    ImmTy::from_immediate(ptr_imm, ty).into()
-                } else if matches!(
-                    ty.backend_repr,
-                    BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)
-                ) {
+                let variant = if ty.ty.is_enum() { Some(variant) } else { None };
+                if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
+                {
                     let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
                     let variant_dest = if let Some(variant) = variant {
                         self.ecx.project_downcast(&dest, variant).discard_err()?
@@ -446,32 +430,46 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     return None;
                 }
             }
+            RawPtr { pointer, metadata } => {
+                let pointer = self.evaluated[pointer].as_ref()?;
+                let metadata = self.evaluated[metadata].as_ref()?;
+
+                // Pointers don't have fields, so don't `project_field` them.
+                let data = self.ecx.read_pointer(pointer).discard_err()?;
+                let meta = if metadata.layout.is_zst() {
+                    MemPlaceMeta::None
+                } else {
+                    MemPlaceMeta::Meta(self.ecx.read_scalar(metadata).discard_err()?)
+                };
+                let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
+                ImmTy::from_immediate(ptr_imm, ty).into()
+            }
 
             Projection(base, elem) => {
-                let value = self.evaluated[base].as_ref()?;
+                let base = self.evaluated[base].as_ref()?;
                 let elem = match elem {
                     ProjectionElem::Deref => ProjectionElem::Deref,
                     ProjectionElem::Downcast(name, read_variant) => {
                         ProjectionElem::Downcast(name, read_variant)
                     }
-                    ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty),
+                    ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
                         ProjectionElem::ConstantIndex { offset, min_length, from_end }
                     }
                     ProjectionElem::Subslice { from, to, from_end } => {
                         ProjectionElem::Subslice { from, to, from_end }
                     }
-                    ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
-                    ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
-                    ProjectionElem::UnwrapUnsafeBinder(ty) => {
-                        ProjectionElem::UnwrapUnsafeBinder(ty)
+                    ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty),
+                    ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty),
+                    ProjectionElem::UnwrapUnsafeBinder(()) => {
+                        ProjectionElem::UnwrapUnsafeBinder(ty.ty)
                     }
                     // This should have been replaced by a `ConstantIndex` earlier.
                     ProjectionElem::Index(_) => return None,
                 };
-                self.ecx.project(value, elem).discard_err()?
+                self.ecx.project(base, elem).discard_err()?
             }
-            Address { place, kind, provenance: _ } => {
+            Address { place, kind: _, provenance: _ } => {
                 if !place.is_indirect_first_projection() {
                     return None;
                 }
@@ -487,19 +485,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     mplace = self.ecx.project(&mplace, proj).discard_err()?;
                 }
                 let pointer = mplace.to_ref(&self.ecx);
-                let ty = match kind {
-                    AddressKind::Ref(bk) => Ty::new_ref(
-                        self.tcx,
-                        self.tcx.lifetimes.re_erased,
-                        mplace.layout.ty,
-                        bk.to_mutbl_lossy(),
-                    ),
-                    AddressKind::Address(mutbl) => {
-                        Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl.to_mutbl_lossy())
-                    }
-                };
-                let layout = self.ecx.layout_of(ty).ok()?;
-                ImmTy::from_immediate(pointer, layout).into()
+                ImmTy::from_immediate(pointer, ty).into()
             }
 
             Discriminant(base) => {
@@ -511,32 +497,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
             Len(slice) => {
                 let slice = self.evaluated[slice].as_ref()?;
-                let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
                 let len = slice.len(&self.ecx).discard_err()?;
-                let imm = ImmTy::from_uint(len, usize_layout);
-                imm.into()
+                ImmTy::from_uint(len, ty).into()
             }
-            NullaryOp(null_op, ty) => {
-                let layout = self.ecx.layout_of(ty).ok()?;
+            NullaryOp(null_op, arg_ty) => {
+                let arg_layout = self.ecx.layout_of(arg_ty).ok()?;
                 if let NullOp::SizeOf | NullOp::AlignOf = null_op
-                    && layout.is_unsized()
+                    && arg_layout.is_unsized()
                 {
                     return None;
                 }
                 let val = match null_op {
-                    NullOp::SizeOf => layout.size.bytes(),
-                    NullOp::AlignOf => layout.align.abi.bytes(),
+                    NullOp::SizeOf => arg_layout.size.bytes(),
+                    NullOp::AlignOf => arg_layout.align.abi.bytes(),
                     NullOp::OffsetOf(fields) => self
                         .ecx
                         .tcx
-                        .offset_of_subfield(self.typing_env(), layout, fields.iter())
+                        .offset_of_subfield(self.typing_env(), arg_layout, fields.iter())
                         .bytes(),
                     NullOp::UbChecks => return None,
                     NullOp::ContractChecks => return None,
                 };
-                let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
-                let imm = ImmTy::from_uint(val, usize_layout);
-                imm.into()
+                ImmTy::from_uint(val, ty).into()
             }
             UnaryOp(un_op, operand) => {
                 let operand = self.evaluated[operand].as_ref()?;
@@ -552,30 +534,27 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?;
                 val.into()
             }
-            Cast { kind, value, from: _, to } => match kind {
+            Cast { kind, value } => match kind {
                 CastKind::IntToInt | CastKind::IntToFloat => {
                     let value = self.evaluated[value].as_ref()?;
                     let value = self.ecx.read_immediate(value).discard_err()?;
-                    let to = self.ecx.layout_of(to).ok()?;
-                    let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?;
+                    let res = self.ecx.int_to_int_or_float(&value, ty).discard_err()?;
                     res.into()
                 }
                 CastKind::FloatToFloat | CastKind::FloatToInt => {
                     let value = self.evaluated[value].as_ref()?;
                     let value = self.ecx.read_immediate(value).discard_err()?;
-                    let to = self.ecx.layout_of(to).ok()?;
-                    let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
+                    let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?;
                     res.into()
                 }
                 CastKind::Transmute => {
                     let value = self.evaluated[value].as_ref()?;
-                    let to = self.ecx.layout_of(to).ok()?;
                     // `offset` for immediates generally only supports projections that match the
                     // type of the immediate. However, as a HACK, we exploit that it can also do
                     // limited transmutes: it only works between types with the same layout, and
                     // cannot transmute pointers to integers.
                     if value.as_mplace_or_imm().is_right() {
-                        let can_transmute = match (value.layout.backend_repr, to.backend_repr) {
+                        let can_transmute = match (value.layout.backend_repr, ty.backend_repr) {
                             (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => {
                                 s1.size(&self.ecx) == s2.size(&self.ecx)
                                     && !matches!(s1.primitive(), Primitive::Pointer(..))
@@ -595,13 +574,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                             return None;
                         }
                     }
-                    value.offset(Size::ZERO, to, &self.ecx).discard_err()?
+                    value.offset(Size::ZERO, ty, &self.ecx).discard_err()?
                 }
                 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => {
                     let src = self.evaluated[value].as_ref()?;
-                    let to = self.ecx.layout_of(to).ok()?;
-                    let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?;
-                    self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?;
+                    let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
+                    self.ecx.unsize_into(src, ty, &dest).discard_err()?;
                     self.ecx
                         .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
                         .discard_err()?;
@@ -610,15 +588,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
                     let src = self.evaluated[value].as_ref()?;
                     let src = self.ecx.read_immediate(src).discard_err()?;
-                    let to = self.ecx.layout_of(to).ok()?;
-                    let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?;
+                    let ret = self.ecx.ptr_to_ptr(&src, ty).discard_err()?;
                     ret.into()
                 }
                 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => {
                     let src = self.evaluated[value].as_ref()?;
                     let src = self.ecx.read_immediate(src).discard_err()?;
-                    let to = self.ecx.layout_of(to).ok()?;
-                    ImmTy::from_immediate(*src, to).into()
+                    ImmTy::from_immediate(*src, ty).into()
                 }
                 _ => return None,
             },
@@ -628,31 +604,30 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
     fn project(
         &mut self,
-        place: PlaceRef<'tcx>,
+        place_ty: PlaceTy<'tcx>,
         value: VnIndex,
         proj: PlaceElem<'tcx>,
         from_non_ssa_index: &mut bool,
-    ) -> Option<VnIndex> {
+    ) -> Option<(PlaceTy<'tcx>, VnIndex)> {
+        let projection_ty = place_ty.projection_ty(self.tcx, proj);
         let proj = match proj {
             ProjectionElem::Deref => {
-                let ty = place.ty(self.local_decls, self.tcx).ty;
-                if let Some(Mutability::Not) = ty.ref_mutability()
-                    && let Some(pointee_ty) = ty.builtin_deref(true)
-                    && pointee_ty.is_freeze(self.tcx, self.typing_env())
+                if let Some(Mutability::Not) = place_ty.ty.ref_mutability()
+                    && projection_ty.ty.is_freeze(self.tcx, self.typing_env())
                 {
                     // An immutable borrow `_x` always points to the same value for the
                     // lifetime of the borrow, so we can merge all instances of `*_x`.
-                    return Some(self.insert_deref(value));
+                    return Some((projection_ty, self.insert_deref(projection_ty.ty, value)));
                 } else {
                     return None;
                 }
             }
             ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
-            ProjectionElem::Field(f, ty) => {
-                if let Value::Aggregate(_, _, fields) = self.get(value) {
-                    return Some(fields[f.as_usize()]);
+            ProjectionElem::Field(f, _) => {
+                if let Value::Aggregate(_, fields) = self.get(value) {
+                    return Some((projection_ty, fields[f.as_usize()]));
                 } else if let Value::Projection(outer_value, ProjectionElem::Downcast(_, read_variant)) = self.get(value)
-                    && let Value::Aggregate(_, written_variant, fields) = self.get(*outer_value)
+                    && let Value::Aggregate(written_variant, fields) = self.get(*outer_value)
                     // This pass is not aware of control-flow, so we do not know whether the
                     // replacement we are doing is actually reachable. We could be in any arm of
                     // ```
@@ -670,14 +645,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     // a downcast to an inactive variant.
                     && written_variant == read_variant
                 {
-                    return Some(fields[f.as_usize()]);
+                    return Some((projection_ty, fields[f.as_usize()]));
                 }
-                ProjectionElem::Field(f, ty)
+                ProjectionElem::Field(f, ())
             }
             ProjectionElem::Index(idx) => {
                 if let Value::Repeat(inner, _) = self.get(value) {
                     *from_non_ssa_index |= self.locals[idx].is_none();
-                    return Some(*inner);
+                    return Some((projection_ty, *inner));
                 }
                 let idx = self.locals[idx]?;
                 ProjectionElem::Index(idx)
@@ -685,15 +660,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
                 match self.get(value) {
                     Value::Repeat(inner, _) => {
-                        return Some(*inner);
+                        return Some((projection_ty, *inner));
                     }
-                    Value::Aggregate(AggregateTy::Array, _, operands) => {
+                    Value::Aggregate(_, operands) => {
                         let offset = if from_end {
                             operands.len() - offset as usize
                         } else {
                             offset as usize
                         };
-                        return operands.get(offset).copied();
+                        let value = operands.get(offset).copied()?;
+                        return Some((projection_ty, value));
                     }
                     _ => {}
                 };
@@ -702,12 +678,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             ProjectionElem::Subslice { from, to, from_end } => {
                 ProjectionElem::Subslice { from, to, from_end }
             }
-            ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
-            ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
-            ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
+            ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()),
+            ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()),
+            ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()),
         };
 
-        Some(self.insert(Value::Projection(value, proj)))
+        let value = self.insert(projection_ty.ty, Value::Projection(value, proj));
+        Some((projection_ty, value))
     }
 
     /// Simplify the projection chain if we know better.
@@ -769,6 +746,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         // Invariant: `value` holds the value up-to the `index`th projection excluded.
         let mut value = self.locals[place.local]?;
+        // Invariant: `value` has type `place_ty`, with optional downcast variant if needed.
+        let mut place_ty = PlaceTy::from_ty(self.local_decls[place.local].ty);
         let mut from_non_ssa_index = false;
         for (index, proj) in place.projection.iter().enumerate() {
             if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
@@ -786,8 +765,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 place_ref = PlaceRef { local, projection: &place.projection[index..] };
             }
 
-            let base = PlaceRef { local: place.local, projection: &place.projection[..index] };
-            value = self.project(base, value, proj, &mut from_non_ssa_index)?;
+            (place_ty, value) = self.project(place_ty, value, proj, &mut from_non_ssa_index)?;
         }
 
         if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
@@ -864,14 +842,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 self.simplify_place_projection(place, location);
                 return Some(self.new_pointer(*place, AddressKind::Address(mutbl)));
             }
-            Rvalue::WrapUnsafeBinder(ref mut op, ty) => {
+            Rvalue::WrapUnsafeBinder(ref mut op, _) => {
                 let value = self.simplify_operand(op, location)?;
-                Value::Cast {
-                    kind: CastKind::Transmute,
-                    value,
-                    from: op.ty(self.local_decls, self.tcx),
-                    to: ty,
-                }
+                Value::Cast { kind: CastKind::Transmute, value }
             }
 
             // Operations.
@@ -896,18 +869,17 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             // Unsupported values.
             Rvalue::ThreadLocalRef(..) | Rvalue::ShallowInitBox(..) => return None,
         };
-        debug!(?value);
-        Some(self.insert(value))
+        let ty = rvalue.ty(self.local_decls, self.tcx);
+        Some(self.insert(ty, value))
     }
 
     fn simplify_discriminant(&mut self, place: VnIndex) -> Option<VnIndex> {
-        if let Value::Aggregate(enum_ty, variant, _) = *self.get(place)
-            && let AggregateTy::Def(enum_did, enum_args) = enum_ty
-            && let DefKind::Enum = self.tcx.def_kind(enum_did)
+        let enum_ty = self.ty(place);
+        if enum_ty.is_enum()
+            && let Value::Aggregate(variant, _) = *self.get(place)
         {
-            let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args);
             let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?;
-            return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty));
+            return Some(self.insert_scalar(discr.layout.ty, discr.to_scalar()));
         }
 
         None
@@ -915,12 +887,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
     fn try_as_place_elem(
         &mut self,
-        proj: ProjectionElem<VnIndex, Ty<'tcx>>,
+        ty: Ty<'tcx>,
+        proj: ProjectionElem<VnIndex, ()>,
         loc: Location,
     ) -> Option<PlaceElem<'tcx>> {
         Some(match proj {
             ProjectionElem::Deref => ProjectionElem::Deref,
-            ProjectionElem::Field(idx, ty) => ProjectionElem::Field(idx, ty),
+            ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty),
             ProjectionElem::Index(idx) => {
                 let Some(local) = self.try_as_local(idx, loc) else {
                     return None;
@@ -935,9 +908,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 ProjectionElem::Subslice { from, to, from_end }
             }
             ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
-            ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
-            ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
-            ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
+            ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty),
+            ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty),
+            ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty),
         })
     }
 
@@ -983,8 +956,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         // Allow introducing places with non-constant offsets, as those are still better than
         // reconstructing an aggregate.
-        if let Some(place) = self.try_as_place(copy_from_local_value, location, true)
-            && rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty
+        if self.ty(copy_from_local_value) == rvalue.ty(self.local_decls, self.tcx)
+            && let Some(place) = self.try_as_place(copy_from_local_value, location, true)
         {
             // Avoid creating `*a = copy (*b)`, as they might be aliases resulting in overlapping assignments.
             // FIXME: This also avoids any kind of projection, not just derefs. We can add allowed projections.
@@ -1004,9 +977,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         rvalue: &mut Rvalue<'tcx>,
         location: Location,
     ) -> Option<VnIndex> {
+        let tcx = self.tcx;
+        let ty = rvalue.ty(self.local_decls, tcx);
+
         let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() };
 
-        let tcx = self.tcx;
         if field_ops.is_empty() {
             let is_zst = match *kind {
                 AggregateKind::Array(..)
@@ -1021,87 +996,72 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             };
 
             if is_zst {
-                let ty = rvalue.ty(self.local_decls, tcx);
                 return Some(self.insert_constant(Const::zero_sized(ty)));
             }
         }
 
-        let (mut ty, variant_index) = match *kind {
-            AggregateKind::Array(..) => {
-                assert!(!field_ops.is_empty());
-                (AggregateTy::Array, FIRST_VARIANT)
-            }
-            AggregateKind::Tuple => {
+        let fields: Vec<_> = field_ops
+            .iter_mut()
+            .map(|op| {
+                self.simplify_operand(op, location)
+                    .unwrap_or_else(|| self.new_opaque(op.ty(self.local_decls, self.tcx)))
+            })
+            .collect();
+
+        let variant_index = match *kind {
+            AggregateKind::Array(..) | AggregateKind::Tuple => {
                 assert!(!field_ops.is_empty());
-                (AggregateTy::Tuple, FIRST_VARIANT)
-            }
-            AggregateKind::Closure(did, args)
-            | AggregateKind::CoroutineClosure(did, args)
-            | AggregateKind::Coroutine(did, args) => (AggregateTy::Def(did, args), FIRST_VARIANT),
-            AggregateKind::Adt(did, variant_index, args, _, None) => {
-                (AggregateTy::Def(did, args), variant_index)
+                FIRST_VARIANT
             }
+            AggregateKind::Closure(..)
+            | AggregateKind::CoroutineClosure(..)
+            | AggregateKind::Coroutine(..) => FIRST_VARIANT,
+            AggregateKind::Adt(_, variant_index, _, _, None) => variant_index,
             // Do not track unions.
             AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
-            AggregateKind::RawPtr(pointee_ty, mtbl) => {
+            AggregateKind::RawPtr(..) => {
                 assert_eq!(field_ops.len(), 2);
-                let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx);
-                let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl);
-                (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT)
-            }
-        };
-
-        let mut fields: Vec<_> = field_ops
-            .iter_mut()
-            .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque()))
-            .collect();
-
-        if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty {
-            let mut was_updated = false;
+                let [mut pointer, metadata] = fields.try_into().unwrap();
+
+                // Any thin pointer of matching mutability is fine as the data pointer.
+                let mut was_updated = false;
+                while let Value::Cast { kind: CastKind::PtrToPtr, value: cast_value } =
+                    self.get(pointer)
+                    && let ty::RawPtr(from_pointee_ty, from_mtbl) = self.ty(*cast_value).kind()
+                    && let ty::RawPtr(_, output_mtbl) = ty.kind()
+                    && from_mtbl == output_mtbl
+                    && from_pointee_ty.is_sized(self.tcx, self.typing_env())
+                {
+                    pointer = *cast_value;
+                    was_updated = true;
+                }
 
-            // Any thin pointer of matching mutability is fine as the data pointer.
-            while let Value::Cast {
-                kind: CastKind::PtrToPtr,
-                value: cast_value,
-                from: cast_from,
-                to: _,
-            } = self.get(fields[0])
-                && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind()
-                && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind()
-                && from_mtbl == output_mtbl
-                && from_pointee_ty.is_sized(self.tcx, self.typing_env())
-            {
-                fields[0] = *cast_value;
-                *data_pointer_ty = *cast_from;
-                was_updated = true;
-            }
+                if was_updated && let Some(op) = self.try_as_operand(pointer, location) {
+                    field_ops[FieldIdx::ZERO] = op;
+                }
 
-            if was_updated && let Some(op) = self.try_as_operand(fields[0], location) {
-                field_ops[FieldIdx::ZERO] = op;
+                return Some(self.insert(ty, Value::RawPtr { pointer, metadata }));
             }
-        }
+        };
 
-        if let AggregateTy::Array = ty
-            && fields.len() > 4
-        {
+        if ty.is_array() && fields.len() > 4 {
             let first = fields[0];
             if fields.iter().all(|&v| v == first) {
                 let len = ty::Const::from_target_usize(self.tcx, fields.len().try_into().unwrap());
                 if let Some(op) = self.try_as_operand(first, location) {
                     *rvalue = Rvalue::Repeat(op, len);
                 }
-                return Some(self.insert(Value::Repeat(first, len)));
+                return Some(self.insert(ty, Value::Repeat(first, len)));
             }
         }
 
-        if let AggregateTy::Def(_, _) = ty
-            && let Some(value) =
-                self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
+        if let Some(value) =
+            self.simplify_aggregate_to_copy(lhs, rvalue, location, &fields, variant_index)
         {
             return Some(value);
         }
 
-        Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
+        Some(self.insert(ty, Value::Aggregate(variant_index, fields)))
     }
 
     #[instrument(level = "trace", skip(self), ret)]
@@ -1112,6 +1072,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         location: Location,
     ) -> Option<VnIndex> {
         let mut arg_index = self.simplify_operand(arg_op, location)?;
+        let arg_ty = self.ty(arg_index);
+        let ret_ty = op.ty(self.tcx, arg_ty);
 
         // PtrMetadata doesn't care about *const vs *mut vs & vs &mut,
         // so start by removing those distinctions so we can update the `Operand`
@@ -1127,8 +1089,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     // we can't always know exactly what the metadata are.
                     // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`,
                     // it's fine to get a projection as the type.
-                    Value::Cast { kind: CastKind::PtrToPtr, value: inner, from, to }
-                        if self.pointers_have_same_metadata(*from, *to) =>
+                    Value::Cast { kind: CastKind::PtrToPtr, value: inner }
+                        if self.pointers_have_same_metadata(self.ty(*inner), arg_ty) =>
                     {
                         arg_index = *inner;
                         was_updated = true;
@@ -1165,26 +1127,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
                 Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
             }
-            (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
-                return Some(fields[1]);
-            }
+            (UnOp::PtrMetadata, Value::RawPtr { metadata, .. }) => return Some(*metadata),
             // We have an unsizing cast, which assigns the length to wide pointer metadata.
             (
                 UnOp::PtrMetadata,
                 Value::Cast {
                     kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _),
-                    from,
-                    to,
-                    ..
+                    value: inner,
                 },
-            ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind()
-                && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() =>
+            ) if let ty::Slice(..) = arg_ty.builtin_deref(true).unwrap().kind()
+                && let ty::Array(_, len) = self.ty(*inner).builtin_deref(true).unwrap().kind() =>
             {
                 return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
             }
             _ => Value::UnaryOp(op, arg_index),
         };
-        Some(self.insert(value))
+        Some(self.insert(ret_ty, value))
     }
 
     #[instrument(level = "trace", skip(self), ret)]
@@ -1197,25 +1155,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     ) -> Option<VnIndex> {
         let lhs = self.simplify_operand(lhs_operand, location);
         let rhs = self.simplify_operand(rhs_operand, location);
+
         // Only short-circuit options after we called `simplify_operand`
         // on both operands for side effect.
         let mut lhs = lhs?;
         let mut rhs = rhs?;
 
-        let lhs_ty = lhs_operand.ty(self.local_decls, self.tcx);
+        let lhs_ty = self.ty(lhs);
 
         // If we're comparing pointers, remove `PtrToPtr` casts if the from
         // types of both casts and the metadata all match.
         if let BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge = op
             && lhs_ty.is_any_ptr()
-            && let Value::Cast {
-                kind: CastKind::PtrToPtr, value: lhs_value, from: lhs_from, ..
-            } = self.get(lhs)
-            && let Value::Cast {
-                kind: CastKind::PtrToPtr, value: rhs_value, from: rhs_from, ..
-            } = self.get(rhs)
-            && lhs_from == rhs_from
-            && self.pointers_have_same_metadata(*lhs_from, lhs_ty)
+            && let Value::Cast { kind: CastKind::PtrToPtr, value: lhs_value } = self.get(lhs)
+            && let Value::Cast { kind: CastKind::PtrToPtr, value: rhs_value } = self.get(rhs)
+            && let lhs_from = self.ty(*lhs_value)
+            && lhs_from == self.ty(*rhs_value)
+            && self.pointers_have_same_metadata(lhs_from, lhs_ty)
         {
             lhs = *lhs_value;
             rhs = *rhs_value;
@@ -1230,8 +1186,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) {
             return Some(value);
         }
+        let ty = op.ty(self.tcx, lhs_ty, self.ty(rhs));
         let value = Value::BinaryOp(op, lhs, rhs);
-        Some(self.insert(value))
+        Some(self.insert(ty, value))
     }
 
     fn simplify_binary_inner(
@@ -1323,19 +1280,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 | BinOp::Shr,
                 Left(0),
                 _,
-            ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
+            ) => self.insert_scalar(lhs_ty, Scalar::from_uint(0u128, layout.size)),
             // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`.
             (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _)
                 if ones == layout.size.truncate(u128::MAX)
                     || (layout.ty.is_bool() && ones == 1) =>
             {
-                self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
+                self.insert_scalar(lhs_ty, Scalar::from_uint(ones, layout.size))
             }
             // Sub/Xor with itself.
             (BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b)
                 if a == b =>
             {
-                self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
+                self.insert_scalar(lhs_ty, Scalar::from_uint(0u128, layout.size))
             }
             // Comparison:
             // - if both operands can be computed as bits, just compare the bits;
@@ -1349,8 +1306,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         };
 
         if op.is_overflowing() {
+            let ty = Ty::new_tup(self.tcx, &[self.ty(result), self.tcx.types.bool]);
             let false_val = self.insert_bool(false);
-            Some(self.insert_tuple(vec![result, false_val]))
+            Some(self.insert_tuple(ty, vec![result, false_val]))
         } else {
             Some(result)
         }
@@ -1366,9 +1324,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         use CastKind::*;
         use rustc_middle::ty::adjustment::PointerCoercion::*;
 
-        let mut from = initial_operand.ty(self.local_decls, self.tcx);
         let mut kind = *initial_kind;
         let mut value = self.simplify_operand(initial_operand, location)?;
+        let mut from = self.ty(value);
         if from == to {
             return Some(value);
         }
@@ -1376,7 +1334,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind {
             // Each reification of a generic fn may get a different pointer.
             // Do not try to merge them.
-            return Some(self.new_opaque());
+            return Some(self.new_opaque(to));
         }
 
         let mut was_ever_updated = false;
@@ -1399,23 +1357,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             // If a cast just casts away the metadata again, then we can get it by
             // casting the original thin pointer passed to `from_raw_parts`
             if let PtrToPtr = kind
-                && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
-                    self.get(value)
+                && let Value::RawPtr { pointer, .. } = self.get(value)
                 && let ty::RawPtr(to_pointee, _) = to.kind()
                 && to_pointee.is_sized(self.tcx, self.typing_env())
             {
-                from = *data_pointer_ty;
-                value = fields[0];
+                from = self.ty(*pointer);
+                value = *pointer;
                 was_updated_this_iteration = true;
-                if *data_pointer_ty == to {
-                    return Some(fields[0]);
+                if from == to {
+                    return Some(*pointer);
                 }
             }
 
             // Aggregate-then-Transmute can just transmute the original field value,
             // so long as the bytes of a value from only from a single field.
             if let Transmute = kind
-                && let Value::Aggregate(_aggregate_ty, variant_idx, field_values) = self.get(value)
+                && let Value::Aggregate(variant_idx, field_values) = self.get(value)
                 && let Some((field_idx, field_ty)) =
                     self.value_is_all_in_one_field(from, *variant_idx)
             {
@@ -1428,13 +1385,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
 
             // Various cast-then-cast cases can be simplified.
-            if let Value::Cast {
-                kind: inner_kind,
-                value: inner_value,
-                from: inner_from,
-                to: inner_to,
-            } = *self.get(value)
-            {
+            if let Value::Cast { kind: inner_kind, value: inner_value } = *self.get(value) {
+                let inner_from = self.ty(inner_value);
                 let new_kind = match (inner_kind, kind) {
                     // Even if there's a narrowing cast in here that's fine, because
                     // things like `*mut [i32] -> *mut i32 -> *const i32` and
@@ -1443,9 +1395,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     // PtrToPtr-then-Transmute is fine so long as the pointer cast is identity:
                     // `*const T -> *mut T -> NonNull<T>` is fine, but we need to check for narrowing
                     // to skip things like `*const [i32] -> *const i32 -> NonNull<T>`.
-                    (PtrToPtr, Transmute)
-                        if self.pointers_have_same_metadata(inner_from, inner_to) =>
-                    {
+                    (PtrToPtr, Transmute) if self.pointers_have_same_metadata(inner_from, from) => {
                         Some(Transmute)
                     }
                     // Similarly, for Transmute-then-PtrToPtr. Note that we need to check different
@@ -1456,7 +1406,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     // If would be legal to always do this, but we don't want to hide information
                     // from the backend that it'd otherwise be able to use for optimizations.
                     (Transmute, Transmute)
-                        if !self.type_may_have_niche_of_interest_to_backend(inner_to) =>
+                        if !self.type_may_have_niche_of_interest_to_backend(from) =>
                     {
                         Some(Transmute)
                     }
@@ -1485,7 +1435,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             *initial_kind = kind;
         }
 
-        Some(self.insert(Value::Cast { kind, value, from, to }))
+        Some(self.insert(to, Value::Cast { kind, value }))
     }
 
     fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
@@ -1507,18 +1457,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         }
 
         // We have an unsizing cast, which assigns the length to wide pointer metadata.
-        if let Value::Cast { kind, from, to, .. } = self.get(inner)
+        if let Value::Cast { kind, value: from } = self.get(inner)
             && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
-            && let Some(from) = from.builtin_deref(true)
+            && let Some(from) = self.ty(*from).builtin_deref(true)
             && let ty::Array(_, len) = from.kind()
-            && let Some(to) = to.builtin_deref(true)
+            && let Some(to) = self.ty(inner).builtin_deref(true)
             && let ty::Slice(..) = to.kind()
         {
             return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
         }
 
         // Fallback: a symbolic `Len`.
-        Some(self.insert(Value::Len(inner)))
+        Some(self.insert(self.tcx.types.usize, Value::Len(inner)))
     }
 
     fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool {
@@ -1727,7 +1677,7 @@ impl<'tcx> VnState<'_, 'tcx> {
                 return Some(place);
             } else if let Value::Projection(pointer, proj) = *self.get(index)
                 && (allow_complex_projection || proj.is_stable_offset())
-                && let Some(proj) = self.try_as_place_elem(proj, loc)
+                && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc)
             {
                 projection.push(proj);
                 index = pointer;
@@ -1755,7 +1705,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
         self.simplify_place_projection(place, location);
-        if context.is_mutating_use() && !place.projection.is_empty() {
+        if context.is_mutating_use() && place.is_indirect() {
             // Non-local mutation maybe invalidate deref.
             self.invalidate_derefs();
         }
@@ -1767,36 +1717,42 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
         self.super_operand(operand, location);
     }
 
-    fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
-        if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind {
-            self.simplify_place_projection(lhs, location);
-
-            let value = self.simplify_rvalue(lhs, rvalue, location);
-            let value = if let Some(local) = lhs.as_local()
-                && self.ssa.is_ssa(local)
-                // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
-                // `local` as reusable if we have an exact type match.
-                && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx)
+    fn visit_assign(
+        &mut self,
+        lhs: &mut Place<'tcx>,
+        rvalue: &mut Rvalue<'tcx>,
+        location: Location,
+    ) {
+        self.simplify_place_projection(lhs, location);
+
+        let value = self.simplify_rvalue(lhs, rvalue, location);
+        if let Some(value) = value {
+            if let Some(const_) = self.try_as_constant(value) {
+                *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
+            } else if let Some(place) = self.try_as_place(value, location, false)
+                && *rvalue != Rvalue::Use(Operand::Move(place))
+                && *rvalue != Rvalue::Use(Operand::Copy(place))
             {
-                let value = value.unwrap_or_else(|| self.new_opaque());
-                self.assign(local, value);
-                Some(value)
-            } else {
-                value
-            };
-            if let Some(value) = value {
-                if let Some(const_) = self.try_as_constant(value) {
-                    *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
-                } else if let Some(place) = self.try_as_place(value, location, false)
-                    && *rvalue != Rvalue::Use(Operand::Move(place))
-                    && *rvalue != Rvalue::Use(Operand::Copy(place))
-                {
-                    *rvalue = Rvalue::Use(Operand::Copy(place));
-                    self.reused_locals.insert(place.local);
-                }
+                *rvalue = Rvalue::Use(Operand::Copy(place));
+                self.reused_locals.insert(place.local);
             }
         }
-        self.super_statement(stmt, location);
+
+        if lhs.is_indirect() {
+            // Non-local mutation maybe invalidate deref.
+            self.invalidate_derefs();
+        }
+
+        if let Some(local) = lhs.as_local()
+            && self.ssa.is_ssa(local)
+            && let rvalue_ty = rvalue.ty(self.local_decls, self.tcx)
+            // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
+            // `local` as reusable if we have an exact type match.
+            && self.local_decls[local].ty == rvalue_ty
+        {
+            let value = value.unwrap_or_else(|| self.new_opaque(rvalue_ty));
+            self.assign(local, value);
+        }
     }
 
     fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
@@ -1804,7 +1760,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
             if let Some(local) = destination.as_local()
                 && self.ssa.is_ssa(local)
             {
-                let opaque = self.new_opaque();
+                let ty = self.local_decls[local].ty;
+                let opaque = self.new_opaque(ty);
                 self.assign(local, opaque);
             }
         }
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_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index cbb9bbfd12f..659ca4df159 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -119,14 +119,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
     #[track_caller]
     fn fail(&self, location: Location, msg: impl AsRef<str>) {
         // We might see broken MIR when other errors have already occurred.
-        assert!(
-            self.tcx.dcx().has_errors().is_some(),
-            "broken MIR in {:?} ({}) at {:?}:\n{}",
-            self.body.source.instance,
-            self.when,
-            location,
-            msg.as_ref(),
-        );
+        if self.tcx.dcx().has_errors().is_none() {
+            span_bug!(
+                self.body.source_info(location).span,
+                "broken MIR in {:?} ({}) at {:?}:\n{}",
+                self.body.source.instance,
+                self.when,
+                location,
+                msg.as_ref(),
+            );
+        }
     }
 
     fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index b42587618b5..ce9b794d40d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -22,6 +22,7 @@ use crate::delegate::SolverDelegate;
 use crate::placeholder::BoundVarReplacer;
 use crate::solve::inspect::{self, ProofTreeBuilder};
 use crate::solve::search_graph::SearchGraph;
+use crate::solve::ty::may_use_unstable_feature;
 use crate::solve::{
     CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
     GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
@@ -550,6 +551,9 @@ where
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
                     self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
                 }
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
+                    self.compute_unstable_feature_goal(param_env, symbol)
+                }
                 ty::PredicateKind::Subtype(predicate) => {
                     self.compute_subtype_goal(Goal { param_env, predicate })
                 }
@@ -1177,6 +1181,14 @@ where
     ) -> T {
         BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0
     }
+
+    pub(super) fn may_use_unstable_feature(
+        &self,
+        param_env: I::ParamEnv,
+        symbol: I::Symbol,
+    ) -> bool {
+        may_use_unstable_feature(&**self.delegate, param_env, symbol)
+    }
 }
 
 /// Eagerly replace aliases with inference variables, emitting `AliasRelate`
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index e68ea22c7a2..5ea3f0d1061 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -148,6 +148,20 @@ where
         }
     }
 
+    fn compute_unstable_feature_goal(
+        &mut self,
+        param_env: <I as Interner>::ParamEnv,
+        symbol: <I as Interner>::Symbol,
+    ) -> QueryResult<I> {
+        if self.may_use_unstable_feature(param_env, symbol) {
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        } else {
+            self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
+                MaybeCause::Ambiguity,
+            ))
+        }
+    }
+
     #[instrument(level = "trace", skip(self))]
     fn compute_const_evaluatable_goal(
         &mut self,
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/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index c4a0ae2ce9d..a92012f8329 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index af9f8735549..859118a4ade 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -855,6 +855,7 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
     .suggestion = remove the `{$token}`
 
 parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
+parse_trait_alias_cannot_be_const = trait aliases cannot be `const`
 parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
 
 parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 7f1b0991f0c..4aaaba01fae 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1962,6 +1962,14 @@ pub(crate) struct TraitAliasCannotBeAuto {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_trait_alias_cannot_be_const)]
+pub(crate) struct TraitAliasCannotBeConst {
+    #[primary_span]
+    #[label(parse_trait_alias_cannot_be_const)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_trait_alias_cannot_be_unsafe)]
 pub(crate) struct TraitAliasCannotBeUnsafe {
     #[primary_span]
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_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index d6cc98d505c..b767b0fcf99 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -244,6 +244,9 @@ impl<'a> Parser<'a> {
             self.bump(); // `static`
             let mutability = self.parse_mutability();
             self.parse_static_item(safety, mutability)?
+        } else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() {
+            // TRAIT ITEM
+            self.parse_item_trait(attrs, lo)?
         } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
             // CONST ITEM
             if self.token.is_keyword(kw::Impl) {
@@ -262,9 +265,6 @@ impl<'a> Parser<'a> {
                     define_opaque: None,
                 }))
             }
-        } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() {
-            // TRAIT ITEM
-            self.parse_item_trait(attrs, lo)?
         } else if self.check_keyword(exp!(Impl))
             || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl])
         {
@@ -373,7 +373,7 @@ impl<'a> Parser<'a> {
     pub(super) fn is_path_start_item(&mut self) -> bool {
         self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
         || self.is_reuse_path_item()
-        || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
+        || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }`
         || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
         || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
     }
@@ -872,16 +872,19 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Is this an `(unsafe auto? | auto) trait` item?
-    fn check_auto_or_unsafe_trait_item(&mut self) -> bool {
+    /// Is this an `(const unsafe? auto?| unsafe auto? | auto) trait` item?
+    fn check_trait_front_matter(&mut self) -> bool {
         // auto trait
         self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait])
             // unsafe auto trait
             || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
+            || self.check_keyword(exp!(Const)) && ((self.is_keyword_ahead(1, &[kw::Trait]) || self.is_keyword_ahead(1, &[kw::Auto]) && self.is_keyword_ahead(2, &[kw::Trait]))
+                || self.is_keyword_ahead(1, &[kw::Unsafe]) && self.is_keyword_ahead(2, &[kw::Trait, kw::Auto]))
     }
 
     /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> {
+        let constness = self.parse_constness(Case::Sensitive);
         let safety = self.parse_safety(Case::Sensitive);
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(exp!(Auto)) {
@@ -913,6 +916,9 @@ impl<'a> Parser<'a> {
             self.expect_semi()?;
 
             let whole_span = lo.to(self.prev_token.span);
+            if let Const::Yes(_) = constness {
+                self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span });
+            }
             if is_auto == IsAuto::Yes {
                 self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });
             }
@@ -927,7 +933,15 @@ impl<'a> Parser<'a> {
             // It's a normal trait.
             generics.where_clause = self.parse_where_clause()?;
             let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
-            Ok(ItemKind::Trait(Box::new(Trait { is_auto, safety, ident, generics, bounds, items })))
+            Ok(ItemKind::Trait(Box::new(Trait {
+                constness,
+                is_auto,
+                safety,
+                ident,
+                generics,
+                bounds,
+                items,
+            })))
         }
     }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 783d79d978a..a476f0db37e 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -318,6 +318,7 @@ pub fn check_builtin_meta_item(
                 | sym::rustc_layout_scalar_valid_range_end
                 | sym::no_implicit_prelude
                 | sym::automatically_derived
+                | sym::coverage
         ) {
             return;
         }
diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml
index 0666ae29409..d178fcda1fb 100644
--- a/compiler/rustc_parse_format/Cargo.toml
+++ b/compiler/rustc_parse_format/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 rustc_lexer = { path = "../rustc_lexer" }
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3418d997b83..51e23edb9bb 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -560,7 +560,8 @@ passes_only_has_effect_on =
     `#[{$attr_name}]` only has an effect on {$target_name ->
         [function] functions
         [module] modules
-        [implementation_block] implementation blocks
+        [trait_implementation_block] trait implementation blocks
+        [inherent_implementation_block] inherent implementation blocks
         *[unspecified] (unspecified--this is a compiler bug)
     }
 
@@ -667,6 +668,10 @@ passes_rustc_std_internal_symbol =
     attribute should be applied to functions or statics
     .label = not a function or static
 
+passes_rustc_unstable_feature_bound =
+    attribute should be applied to `impl` or free function outside of any `impl` or trait
+    .label = not an `impl` or free function
+
 passes_should_be_applied_to_fn =
     attribute should be applied to a function definition
     .label = {$on_crate ->
@@ -780,7 +785,7 @@ passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never r
     .help = did you mean to capture by reference instead?
 
 passes_unused_default_method_body_const_note =
-    `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
+    `default_method_body_is_const` has been replaced with `const` on traits
 
 passes_unused_duplicate =
     unused attribute
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2009ddc1e2d..3ec6a1124a6 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,12 +10,18 @@ use std::collections::hash_map::Entry;
 use std::slice;
 
 use rustc_abi::{Align, ExternAbi, Size};
-use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast};
-use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr};
+use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast, join_path_syms};
+use rustc_attr_data_structures::{
+    AttributeKind, InlineAttr, PartialConstStability, ReprAttr, Stability, StabilityLevel,
+    find_attr,
+};
 use rustc_attr_parsing::{AttributeParser, Late};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
-use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
+use rustc_feature::{
+    ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
+    BuiltinAttribute,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -36,6 +42,7 @@ use rustc_session::lint;
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
     MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
+    USELESS_DEPRECATED,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::edition::Edition;
@@ -161,12 +168,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         sym::automatically_derived,
                         *attr_span,
                         target,
-                        Target::Impl,
+                        Target::Impl { of_trait: true },
                     ),
                 Attribute::Parsed(
-                    AttributeKind::Stability { span, .. }
-                    | AttributeKind::ConstStability { span, .. },
-                ) => self.check_stability_promotable(*span, target),
+                    AttributeKind::Stability {
+                        span: attr_span,
+                        stability: Stability { level, feature },
+                    }
+                    | AttributeKind::ConstStability {
+                        span: attr_span,
+                        stability: PartialConstStability { level, feature, .. },
+                    },
+                ) => self.check_stability(*attr_span, span, level, *feature, target),
                 Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below
                 Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
                     self.check_inline(hir_id, *attr_span, span, kind, target)
@@ -247,6 +260,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 &Attribute::Parsed(AttributeKind::FfiPure(attr_span)) => {
                     self.check_ffi_pure(attr_span, attrs, target)
                 }
+                Attribute::Parsed(AttributeKind::UnstableFeatureBound(syms)) => {
+                    self.check_unstable_feature_bound(syms.first().unwrap().1, span, target)
+                }
                 Attribute::Parsed(
                     AttributeKind::BodyStability { .. }
                     | AttributeKind::ConstStabilityIndirect
@@ -285,6 +301,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 &Attribute::Parsed(AttributeKind::StdInternalSymbol(attr_span)) => {
                     self.check_rustc_std_internal_symbol(attr_span, span, target)
                 }
+                &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => {
+                    self.check_coverage(attr_span, span, target)
+                }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
                     match attr.path().as_slice() {
@@ -294,7 +313,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::diagnostic, sym::on_unimplemented, ..] => {
                             self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
                         }
-                        [sym::coverage, ..] => self.check_coverage(attr, span, target),
                         [sym::no_sanitize, ..] => {
                             self.check_no_sanitize(attr, span, target)
                         }
@@ -489,7 +507,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         attr: &Attribute,
         item: Option<ItemLike<'_>>,
     ) {
-        if !matches!(target, Target::Impl)
+        if !matches!(target, Target::Impl { .. })
             || matches!(
                 item,
                 Some(ItemLike::Item(hir::Item {  kind: hir::ItemKind::Impl(_impl),.. }))
@@ -585,7 +603,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
     /// Checks that `#[coverage(..)]` is applied to a function/closure/method,
     /// or to an impl block or module.
-    fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
+    fn check_coverage(&self, attr_span: Span, target_span: Span, target: Target) {
         let mut not_fn_impl_mod = None;
         let mut no_body = None;
 
@@ -593,7 +611,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Target::Fn
             | Target::Closure
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
-            | Target::Impl
+            | Target::Impl { .. }
             | Target::Mod => return,
 
             // These are "functions", but they aren't allowed because they don't
@@ -608,7 +626,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
 
         self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
-            attr_span: attr.span(),
+            attr_span,
             not_fn_impl_mod,
             no_body,
             help: (),
@@ -678,9 +696,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         allowed_target: Target,
     ) {
         if target != allowed_target {
-            let path = attr.path();
-            let path: Vec<_> = path.iter().map(|s| s.as_str()).collect();
-            let attr_name = path.join("::");
+            let attr_name = join_path_syms(attr.path());
             self.tcx.emit_node_span_lint(
                 UNUSED_ATTRIBUTES,
                 hir_id,
@@ -984,9 +1000,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let span = meta.span();
         if let Some(location) = match target {
             Target::AssocTy => {
-                let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
-                let containing_item = self.tcx.hir_expect_item(parent_def_id);
-                if Target::from_item(containing_item) == Target::Impl {
+                if let DefKind::Impl { .. } =
+                    self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id))
+                {
                     Some("type alias in implementation block")
                 } else {
                     None
@@ -1009,7 +1025,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::Arm
             | Target::ForeignMod
             | Target::Closure
-            | Target::Impl
+            | Target::Impl { .. }
             | Target::WherePredicate => Some(target.name()),
             Target::ExternCrate
             | Target::Use
@@ -1030,7 +1046,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::ForeignFn
             | Target::ForeignStatic
             | Target::ForeignTy
-            | Target::GenericParam(..)
+            | Target::GenericParam { .. }
             | Target::MacroDef
             | Target::PatField
             | Target::ExprField => None,
@@ -1159,7 +1175,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match item.kind {
             ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _)
                 if generics.params.len() != 0 => {}
-            ItemKind::Trait(_, _, _, generics, _, items)
+            ItemKind::Trait(_, _, _, _, generics, _, items)
                 if generics.params.len() != 0
                     || items.iter().any(|item| {
                         matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy)
@@ -1587,7 +1603,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let article = match target {
             Target::ExternCrate
             | Target::Enum
-            | Target::Impl
+            | Target::Impl { .. }
             | Target::Expression
             | Target::Arm
             | Target::AssocConst
@@ -2267,6 +2283,47 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
+    fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) {
+        match target {
+            // FIXME(staged_api): There's no reason we can't support more targets here. We're just
+            // being conservative to begin with.
+            Target::Fn | Target::Impl { .. } => {}
+            Target::ExternCrate
+            | Target::Use
+            | Target::Static
+            | Target::Const
+            | Target::Closure
+            | Target::Mod
+            | Target::ForeignMod
+            | Target::GlobalAsm
+            | Target::TyAlias
+            | Target::Enum
+            | Target::Variant
+            | Target::Struct
+            | Target::Field
+            | Target::Union
+            | Target::Trait
+            | Target::TraitAlias
+            | Target::Expression
+            | Target::Statement
+            | Target::Arm
+            | Target::AssocConst
+            | Target::Method(_)
+            | Target::AssocTy
+            | Target::ForeignFn
+            | Target::ForeignStatic
+            | Target::ForeignTy
+            | Target::GenericParam { .. }
+            | Target::MacroDef
+            | Target::Param
+            | Target::PatField
+            | Target::ExprField
+            | Target::WherePredicate => {
+                self.tcx.dcx().emit_err(errors::RustcUnstableFeatureBound { attr_span, span });
+            }
+        }
+    }
+
     fn check_rustc_std_internal_symbol(&self, attr_span: Span, span: Span, target: Target) {
         match target {
             Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {}
@@ -2276,13 +2333,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_stability_promotable(&self, span: Span, target: Target) {
+    fn check_stability(
+        &self,
+        attr_span: Span,
+        item_span: Span,
+        level: &StabilityLevel,
+        feature: Symbol,
+        target: Target,
+    ) {
         match target {
             Target::Expression => {
-                self.dcx().emit_err(errors::StabilityPromotable { attr_span: span });
+                self.dcx().emit_err(errors::StabilityPromotable { attr_span });
             }
             _ => {}
         }
+
+        // Stable *language* features shouldn't be used as unstable library features.
+        // (Not doing this for stable library features is checked by tidy.)
+        if level.is_unstable()
+            && ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some()
+        {
+            self.tcx
+                .dcx()
+                .emit_err(errors::UnstableAttrForAlreadyStableFeature { attr_span, item_span });
+        }
     }
 
     fn check_link_ordinal(&self, attr_span: Span, _span: Span, target: Target) {
@@ -2310,6 +2384,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     errors::Deprecated,
                 );
             }
+            Target::Impl { of_trait: true }
+            | Target::GenericParam { has_default: false, kind: _ } => {
+                self.tcx.emit_node_span_lint(
+                    USELESS_DEPRECATED,
+                    hir_id,
+                    attr.span(),
+                    errors::DeprecatedAnnotationHasNoEffect { span: attr.span() },
+                );
+            }
+            Target::AssocConst | Target::Method(..) | Target::AssocTy
+                if matches!(
+                    self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)),
+                    DefKind::Impl { of_trait: true }
+                ) =>
+            {
+                self.tcx.emit_node_span_lint(
+                    USELESS_DEPRECATED,
+                    hir_id,
+                    attr.span(),
+                    errors::DeprecatedAnnotationHasNoEffect { span: attr.span() },
+                );
+            }
             _ => {}
         }
     }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 093a2b38804..c6ab6b0d601 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -687,6 +687,15 @@ pub(crate) struct RustcAllowConstFnUnstable {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_rustc_unstable_feature_bound)]
+pub(crate) struct RustcUnstableFeatureBound {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_rustc_std_internal_symbol)]
 pub(crate) struct RustcStdInternalSymbol {
     #[primary_span]
@@ -1364,9 +1373,9 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
     #[primary_span]
     #[label]
     #[help]
-    pub span: Span,
+    pub attr_span: Span,
     #[label(passes_item)]
-    pub item_sp: Span,
+    pub item_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 3afed9784de..6fac01827a4 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -287,7 +287,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
             ast::ItemKind::Union(..) => Target::Union,
             ast::ItemKind::Trait(_) => Target::Trait,
             ast::ItemKind::TraitAlias(..) => Target::TraitAlias,
-            ast::ItemKind::Impl(_) => Target::Impl,
+            ast::ItemKind::Impl(imp_) => Target::Impl { of_trait: imp_.of_trait.is_some() },
             ast::ItemKind::MacroDef(..) => Target::MacroDef,
             ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => {
                 unreachable!("macros should have been expanded")
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 127e0df1332..35d2a655991 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -44,7 +44,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
             StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since {
                 StableSince::Version(v) => Symbol::intern(&v.to_string()),
                 StableSince::Current => sym::env_CFG_RELEASE,
-                StableSince::Err => return None,
+                StableSince::Err(_) => return None,
             }),
         };
 
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index adda94fda8f..40999d622dc 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -1,37 +1,31 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-use std::mem::replace;
 use std::num::NonZero;
 
 use rustc_ast_lowering::stability::extern_abi_stability;
 use rustc_attr_data_structures::{
-    self as attrs, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability,
-    Stability, StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
+    self as attrs, AttributeKind, ConstStability, DefaultBodyStability, DeprecatedSince, Stability,
+    StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
 };
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
-use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
+use rustc_feature::{EnabledLangFeature, EnabledLibFeature};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
-use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor, VisitorExt};
 use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
 use rustc_middle::middle::privacy::EffectiveVisibilities;
-use rustc_middle::middle::stability::{
-    AllowUnstable, Deprecated, DeprecationEntry, EvalResult, Index,
-};
-use rustc_middle::query::Providers;
+use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult};
+use rustc_middle::query::{LocalCrate, Providers};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint;
-use rustc_session::lint::builtin::{
-    DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED,
-};
+use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL};
 use rustc_span::{Span, Symbol, sym};
-use tracing::{debug, info};
+use tracing::instrument;
 
 use crate::errors;
 
@@ -47,359 +41,263 @@ enum AnnotationKind {
     Container,
 }
 
-/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
-/// deprecation, because nested items rarely have individual deprecation attributes, and so
-/// should be treated as deprecated if their parent is. However, default generic parameters
-/// have separate deprecation attributes from their parents, so we do not wish to inherit
-/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
-/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
-#[derive(Clone)]
-enum InheritDeprecation {
-    Yes,
-    No,
+fn inherit_deprecation(def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => false,
+        _ => true,
+    }
 }
 
-impl InheritDeprecation {
-    fn yes(&self) -> bool {
-        matches!(self, InheritDeprecation::Yes)
+fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    let def_kind = tcx.def_kind(def_id);
+    match def_kind {
+        DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
+            match tcx.def_kind(tcx.local_parent(def_id)) {
+                DefKind::Impl { of_trait: true } => true,
+                _ => false,
+            }
+        }
+        _ => false,
     }
 }
 
-/// Whether to inherit const stability flags for nested items. In most cases, we do not want to
-/// inherit const stability: just because an enclosing `fn` is const-stable does not mean
-/// all `extern` imports declared in it should be const-stable! However, trait methods
-/// inherit const stability attributes from their parent and do not have their own.
-enum InheritConstStability {
-    Yes,
-    No,
-}
+fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind {
+    let def_kind = tcx.def_kind(def_id);
+    match def_kind {
+        // Inherent impls and foreign modules serve only as containers for other items,
+        // they don't have their own stability. They still can be annotated as unstable
+        // and propagate this unstability to children, but this annotation is completely
+        // optional. They inherit stability from their parents when unannotated.
+        DefKind::Impl { of_trait: false } | DefKind::ForeignMod => AnnotationKind::Container,
+        DefKind::Impl { of_trait: true } => AnnotationKind::DeprecationProhibited,
+
+        // Allow stability attributes on default generic arguments.
+        DefKind::TyParam | DefKind::ConstParam => {
+            match &tcx.hir_node_by_def_id(def_id).expect_generic_param().kind {
+                hir::GenericParamKind::Type { default: Some(_), .. }
+                | hir::GenericParamKind::Const { default: Some(_), .. } => {
+                    AnnotationKind::Container
+                }
+                _ => AnnotationKind::Prohibited,
+            }
+        }
+
+        // Impl items in trait impls cannot have stability.
+        DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst => {
+            match tcx.def_kind(tcx.local_parent(def_id)) {
+                DefKind::Impl { of_trait: true } => AnnotationKind::Prohibited,
+                _ => AnnotationKind::Required,
+            }
+        }
 
-impl InheritConstStability {
-    fn yes(&self) -> bool {
-        matches!(self, InheritConstStability::Yes)
+        _ => AnnotationKind::Required,
     }
 }
 
-enum InheritStability {
-    Yes,
-    No,
-}
+fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DeprecationEntry> {
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
+    let depr = attrs::find_attr!(attrs,
+        AttributeKind::Deprecation { deprecation, span: _ } => *deprecation
+    );
 
-impl InheritStability {
-    fn yes(&self) -> bool {
-        matches!(self, InheritStability::Yes)
-    }
+    let Some(depr) = depr else {
+        if inherit_deprecation(tcx.def_kind(def_id)) {
+            let parent_id = tcx.opt_local_parent(def_id)?;
+            let parent_depr = tcx.lookup_deprecation_entry(parent_id)?;
+            return Some(parent_depr);
+        }
+
+        return None;
+    };
+
+    // `Deprecation` is just two pointers, no need to intern it
+    Some(DeprecationEntry::local(depr, def_id))
 }
 
-/// A private tree-walker for producing an `Index`.
-struct Annotator<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    index: &'a mut Index,
-    parent_stab: Option<Stability>,
-    parent_const_stab: Option<ConstStability>,
-    parent_depr: Option<DeprecationEntry>,
-    in_trait_impl: bool,
+fn inherit_stability(def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => true,
+        _ => false,
+    }
 }
 
-impl<'a, 'tcx> Annotator<'a, 'tcx> {
-    /// Determine the stability for a node based on its attributes and inherited stability. The
-    /// stability is recorded in the index and used as the parent. If the node is a function,
-    /// `fn_sig` is its signature.
-    fn annotate<F>(
-        &mut self,
-        def_id: LocalDefId,
-        item_sp: Span,
-        fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
-        kind: AnnotationKind,
-        inherit_deprecation: InheritDeprecation,
-        inherit_const_stability: InheritConstStability,
-        inherit_from_parent: InheritStability,
-        visit_children: F,
-    ) where
-        F: FnOnce(&mut Self),
-    {
-        let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
-        debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
-
-        let depr = attrs::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
-        let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
-
-        let mut is_deprecated = false;
-        if let Some((depr, span)) = &depr {
-            is_deprecated = true;
-
-            if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) {
-                let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
-                self.tcx.emit_node_span_lint(
-                    USELESS_DEPRECATED,
-                    hir_id,
-                    *span,
-                    errors::DeprecatedAnnotationHasNoEffect { span: *span },
-                );
-            }
+/// If the `-Z force-unstable-if-unmarked` flag is passed then we provide
+/// a parent stability annotation which indicates that this is private
+/// with the `rustc_private` feature. This is intended for use when
+/// compiling library and `rustc_*` crates themselves so we can leverage crates.io
+/// while maintaining the invariant that all sysroot crates are unstable
+/// by default and are unable to be used.
+const FORCE_UNSTABLE: Stability = Stability {
+    level: attrs::StabilityLevel::Unstable {
+        reason: UnstableReason::Default,
+        issue: NonZero::new(27812),
+        is_soft: false,
+        implied_by: None,
+        old_name: None,
+    },
+    feature: sym::rustc_private,
+};
 
-            // `Deprecation` is just two pointers, no need to intern it
-            let depr_entry = DeprecationEntry::local(*depr, def_id);
-            self.index.depr_map.insert(def_id, depr_entry);
-        } else if let Some(parent_depr) = self.parent_depr {
-            if inherit_deprecation.yes() {
-                is_deprecated = true;
-                info!("tagging child {:?} as deprecated from parent", def_id);
-                self.index.depr_map.insert(def_id, parent_depr);
-            }
+#[instrument(level = "debug", skip(tcx))]
+fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Stability> {
+    // Propagate unstability. This can happen even for non-staged-api crates in case
+    // -Zforce-unstable-if-unmarked is set.
+    if !tcx.features().staged_api() {
+        if !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
+            return None;
         }
 
-        if !self.tcx.features().staged_api() {
-            // Propagate unstability. This can happen even for non-staged-api crates in case
-            // -Zforce-unstable-if-unmarked is set.
-            if let Some(stab) = self.parent_stab {
-                if inherit_deprecation.yes() && stab.is_unstable() {
-                    self.index.stab_map.insert(def_id, stab);
-                    if fn_sig.is_some_and(|s| s.header.is_const()) {
-                        self.index.const_stab_map.insert(
-                            def_id,
-                            ConstStability::unmarked(const_stability_indirect, stab),
-                        );
-                    }
-                }
-            }
+        let Some(parent) = tcx.opt_local_parent(def_id) else { return Some(FORCE_UNSTABLE) };
 
-            self.recurse_with_stability_attrs(
-                depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
-                None,
-                None,
-                visit_children,
-            );
-            return;
+        if inherit_deprecation(tcx.def_kind(def_id)) {
+            let parent = tcx.lookup_stability(parent)?;
+            if parent.is_unstable() {
+                return Some(parent);
+            }
         }
 
-        // # Regular and body stability
-        let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span));
-        let body_stab =
-            attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability);
+        return None;
+    }
 
-        if let Some((depr, span)) = &depr
-            && depr.is_since_rustc_version()
-            && stab.is_none()
-        {
-            self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span });
-        }
+    // # Regular stability
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
+    let stab =
+        attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability);
 
-        if let Some(body_stab) = body_stab {
-            // FIXME: check that this item can have body stability
+    if let Some(stab) = stab {
+        return Some(stab);
+    }
 
-            self.index.default_body_stab_map.insert(def_id, body_stab);
-            debug!(?self.index.default_body_stab_map);
+    if inherit_deprecation(tcx.def_kind(def_id)) {
+        let Some(parent) = tcx.opt_local_parent(def_id) else {
+            return tcx
+                .sess
+                .opts
+                .unstable_opts
+                .force_unstable_if_unmarked
+                .then_some(FORCE_UNSTABLE);
+        };
+        let parent = tcx.lookup_stability(parent)?;
+        if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)) {
+            return Some(parent);
         }
+    }
 
-        let stab = stab.map(|(stab, span)| {
-            // Error if prohibited, or can't inherit anything from a container.
-            if kind == AnnotationKind::Prohibited
-                || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
-            {
-                self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
-            }
+    None
+}
 
-            debug!("annotate: found {:?}", stab);
+#[instrument(level = "debug", skip(tcx))]
+fn lookup_default_body_stability(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> Option<DefaultBodyStability> {
+    if !tcx.features().staged_api() {
+        return None;
+    }
 
-            // Check if deprecated_since < stable_since. If it is,
-            // this is *almost surely* an accident.
-            if let (
-                &Some(DeprecatedSince::RustcVersion(dep_since)),
-                &attrs::StabilityLevel::Stable { since: stab_since, .. },
-            ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level)
-            {
-                match stab_since {
-                    StableSince::Current => {
-                        self.tcx
-                            .dcx()
-                            .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
-                    }
-                    StableSince::Version(stab_since) => {
-                        if dep_since < stab_since {
-                            self.tcx
-                                .dcx()
-                                .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
-                        }
-                    }
-                    StableSince::Err => {
-                        // An error already reported. Assume the unparseable stabilization
-                        // version is older than the deprecation version.
-                    }
-                }
-            }
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
+    // FIXME: check that this item can have body stability
+    attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability)
+}
 
-            // Stable *language* features shouldn't be used as unstable library features.
-            // (Not doing this for stable library features is checked by tidy.)
-            if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab {
-                if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
-                    self.tcx
-                        .dcx()
-                        .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp });
-                }
-            }
-            if let Stability {
-                level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
-                feature,
-            } = stab
+#[instrument(level = "debug", skip(tcx))]
+fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstStability> {
+    if !tcx.features().staged_api() {
+        // Propagate unstability. This can happen even for non-staged-api crates in case
+        // -Zforce-unstable-if-unmarked is set.
+        if inherit_deprecation(tcx.def_kind(def_id)) {
+            let parent = tcx.opt_local_parent(def_id)?;
+            let parent_stab = tcx.lookup_stability(parent)?;
+            if parent_stab.is_unstable()
+                && let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
+                && fn_sig.header.is_const()
             {
-                self.index.implications.insert(implied_by, feature);
-            }
-
-            self.index.stab_map.insert(def_id, stab);
-            stab
-        });
-
-        if stab.is_none() {
-            debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
-            if let Some(stab) = self.parent_stab {
-                if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
-                    self.index.stab_map.insert(def_id, stab);
-                }
+                let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
+                let const_stability_indirect =
+                    find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
+                return Some(ConstStability::unmarked(const_stability_indirect, parent_stab));
             }
         }
 
-        let final_stab = self.index.stab_map.get(&def_id);
+        return None;
+    }
 
-        // # Const stability
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
+    let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
+    let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability);
+
+    // After checking the immediate attributes, get rid of the span and compute implied
+    // const stability: inherit feature gate from regular stability.
+    let mut const_stab = const_stab
+        .map(|const_stab| ConstStability::from_partial(const_stab, const_stability_indirect));
+
+    // If this is a const fn but not annotated with stability markers, see if we can inherit
+    // regular stability.
+    if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
+        && fn_sig.header.is_const()
+        && const_stab.is_none()
+        // We only ever inherit unstable features.
+        && let Some(inherit_regular_stab) = tcx.lookup_stability(def_id)
+        && inherit_regular_stab.is_unstable()
+    {
+        const_stab = Some(ConstStability {
+            // We subject these implicitly-const functions to recursive const stability.
+            const_stable_indirect: true,
+            promotable: false,
+            level: inherit_regular_stab.level,
+            feature: inherit_regular_stab.feature,
+        });
+    }
 
-        let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span));
+    if let Some(const_stab) = const_stab {
+        return Some(const_stab);
+    }
 
-        // If the current node is a function with const stability attributes (directly given or
-        // implied), check if the function/method is const or the parent impl block is const.
-        if let Some(fn_sig) = fn_sig
-            && !fn_sig.header.is_const()
-            && const_stab.is_some()
-        {
-            self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
+    // `impl const Trait for Type` items forward their const stability to their immediate children.
+    // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
+    // Currently, once that is set, we do not inherit anything from the parent any more.
+    if inherit_const_stability(tcx, def_id) {
+        let parent = tcx.opt_local_parent(def_id)?;
+        let parent = tcx.lookup_const_stability(parent)?;
+        if parent.is_const_unstable() {
+            return Some(parent);
         }
+    }
 
-        // If this is marked const *stable*, it must also be regular-stable.
-        if let Some((const_stab, const_span)) = const_stab
-            && let Some(fn_sig) = fn_sig
-            && const_stab.is_const_stable()
-            && !stab.is_some_and(|s| s.is_stable())
-        {
-            self.tcx
-                .dcx()
-                .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
-        }
+    None
+}
 
-        // Stable *language* features shouldn't be used as unstable library features.
-        // (Not doing this for stable library features is checked by tidy.)
-        if let Some((
-            PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. },
-            const_span,
-        )) = const_stab
-        {
-            if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
-                self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
-                    span: const_span,
-                    item_sp,
-                });
-            }
-        }
+/// A private tree-walker for producing an `Index`.
+struct Annotator<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    implications: UnordMap<Symbol, Symbol>,
+}
 
-        if let Some((stab, span)) = &const_stab
-            && stab.is_const_stable()
-            && const_stability_indirect
-        {
-            self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span });
+impl<'tcx> Annotator<'tcx> {
+    /// Determine the stability for a node based on its attributes and inherited stability. The
+    /// stability is recorded in the index and used as the parent. If the node is a function,
+    /// `fn_sig` is its signature.
+    #[instrument(level = "trace", skip(self))]
+    fn annotate(&mut self, def_id: LocalDefId) {
+        if !self.tcx.features().staged_api() {
+            return;
         }
 
-        // After checking the immediate attributes, get rid of the span and compute implied
-        // const stability: inherit feature gate from regular stability.
-        let mut const_stab = const_stab
-            .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect));
-
-        // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
-        if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
-            // We only ever inherit unstable features.
-            let Some(inherit_regular_stab) =
-                final_stab.filter(|s| s.is_unstable())
+        if let Some(stability) = self.tcx.lookup_stability(def_id)
+            && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
         {
-            const_stab = Some(ConstStability {
-                // We subject these implicitly-const functions to recursive const stability.
-                const_stable_indirect: true,
-                promotable: false,
-                level: inherit_regular_stab.level,
-                feature: inherit_regular_stab.feature,
-            });
+            self.implications.insert(implied_by, stability.feature);
         }
 
-        // Now that everything is computed, insert it into the table.
-        const_stab.inspect(|const_stab| {
-            self.index.const_stab_map.insert(def_id, *const_stab);
-        });
-
-        if let Some(ConstStability {
-            level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
-            feature,
-            ..
-        }) = const_stab
+        if let Some(stability) = self.tcx.lookup_const_stability(def_id)
+            && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
         {
-            self.index.implications.insert(implied_by, feature);
-        }
-
-        // `impl const Trait for Type` items forward their const stability to their
-        // immediate children.
-        // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
-        // Currently, once that is set, we do not inherit anything from the parent any more.
-        if const_stab.is_none() {
-            debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
-            if let Some(parent) = self.parent_const_stab {
-                if parent.is_const_unstable() {
-                    self.index.const_stab_map.insert(def_id, parent);
-                }
-            }
-        }
-
-        self.recurse_with_stability_attrs(
-            depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
-            stab,
-            inherit_const_stability.yes().then_some(const_stab).flatten(),
-            visit_children,
-        );
-    }
-
-    fn recurse_with_stability_attrs(
-        &mut self,
-        depr: Option<DeprecationEntry>,
-        stab: Option<Stability>,
-        const_stab: Option<ConstStability>,
-        f: impl FnOnce(&mut Self),
-    ) {
-        // These will be `Some` if this item changes the corresponding stability attribute.
-        let mut replaced_parent_depr = None;
-        let mut replaced_parent_stab = None;
-        let mut replaced_parent_const_stab = None;
-
-        if let Some(depr) = depr {
-            replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
-        }
-        if let Some(stab) = stab {
-            replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
-        }
-        if let Some(const_stab) = const_stab {
-            replaced_parent_const_stab =
-                Some(replace(&mut self.parent_const_stab, Some(const_stab)));
-        }
-
-        f(self);
-
-        if let Some(orig_parent_depr) = replaced_parent_depr {
-            self.parent_depr = orig_parent_depr;
-        }
-        if let Some(orig_parent_stab) = replaced_parent_stab {
-            self.parent_stab = orig_parent_stab;
-        }
-        if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
-            self.parent_const_stab = orig_parent_const_stab;
+            self.implications.insert(implied_by, stability.feature);
         }
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for Annotator<'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
@@ -410,184 +308,51 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     }
 
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
-        let orig_in_trait_impl = self.in_trait_impl;
-        let mut kind = AnnotationKind::Required;
-        let mut const_stab_inherit = InheritConstStability::No;
-        let mut fn_sig = None;
-
         match i.kind {
-            // Inherent impls and foreign modules serve only as containers for other items,
-            // they don't have their own stability. They still can be annotated as unstable
-            // and propagate this instability to children, but this annotation is completely
-            // optional. They inherit stability from their parents when unannotated.
-            hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
-            | hir::ItemKind::ForeignMod { .. } => {
-                self.in_trait_impl = false;
-                kind = AnnotationKind::Container;
-            }
-            hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
-                self.in_trait_impl = true;
-                kind = AnnotationKind::DeprecationProhibited;
-                const_stab_inherit = InheritConstStability::Yes;
-            }
             hir::ItemKind::Struct(_, _, ref sd) => {
                 if let Some(ctor_def_id) = sd.ctor_def_id() {
-                    self.annotate(
-                        ctor_def_id,
-                        i.span,
-                        None,
-                        AnnotationKind::Required,
-                        InheritDeprecation::Yes,
-                        InheritConstStability::No,
-                        InheritStability::Yes,
-                        |_| {},
-                    )
+                    self.annotate(ctor_def_id);
                 }
             }
-            hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => {
-                fn_sig = Some(item_fn_sig);
-            }
             _ => {}
         }
 
-        self.annotate(
-            i.owner_id.def_id,
-            i.span,
-            fn_sig,
-            kind,
-            InheritDeprecation::Yes,
-            const_stab_inherit,
-            InheritStability::No,
-            |v| intravisit::walk_item(v, i),
-        );
-        self.in_trait_impl = orig_in_trait_impl;
+        self.annotate(i.owner_id.def_id);
+        intravisit::walk_item(self, i)
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        let fn_sig = match ti.kind {
-            hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
-            _ => None,
-        };
-
-        self.annotate(
-            ti.owner_id.def_id,
-            ti.span,
-            fn_sig,
-            AnnotationKind::Required,
-            InheritDeprecation::Yes,
-            InheritConstStability::No,
-            InheritStability::No,
-            |v| {
-                intravisit::walk_trait_item(v, ti);
-            },
-        );
+        self.annotate(ti.owner_id.def_id);
+        intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
-        let kind =
-            if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
-
-        let fn_sig = match ii.kind {
-            hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
-            _ => None,
-        };
-
-        self.annotate(
-            ii.owner_id.def_id,
-            ii.span,
-            fn_sig,
-            kind,
-            InheritDeprecation::Yes,
-            InheritConstStability::No,
-            InheritStability::No,
-            |v| {
-                intravisit::walk_impl_item(v, ii);
-            },
-        );
+        self.annotate(ii.owner_id.def_id);
+        intravisit::walk_impl_item(self, ii);
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
-        self.annotate(
-            var.def_id,
-            var.span,
-            None,
-            AnnotationKind::Required,
-            InheritDeprecation::Yes,
-            InheritConstStability::No,
-            InheritStability::Yes,
-            |v| {
-                if let Some(ctor_def_id) = var.data.ctor_def_id() {
-                    v.annotate(
-                        ctor_def_id,
-                        var.span,
-                        None,
-                        AnnotationKind::Required,
-                        InheritDeprecation::Yes,
-                        InheritConstStability::No,
-                        InheritStability::Yes,
-                        |_| {},
-                    );
-                }
+        self.annotate(var.def_id);
+        if let Some(ctor_def_id) = var.data.ctor_def_id() {
+            self.annotate(ctor_def_id);
+        }
 
-                intravisit::walk_variant(v, var)
-            },
-        )
+        intravisit::walk_variant(self, var)
     }
 
     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
-        self.annotate(
-            s.def_id,
-            s.span,
-            None,
-            AnnotationKind::Required,
-            InheritDeprecation::Yes,
-            InheritConstStability::No,
-            InheritStability::Yes,
-            |v| {
-                intravisit::walk_field_def(v, s);
-            },
-        );
+        self.annotate(s.def_id);
+        intravisit::walk_field_def(self, s);
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
-        let fn_sig = match &i.kind {
-            rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
-            _ => None,
-        };
-        self.annotate(
-            i.owner_id.def_id,
-            i.span,
-            fn_sig,
-            AnnotationKind::Required,
-            InheritDeprecation::Yes,
-            InheritConstStability::No,
-            InheritStability::No,
-            |v| {
-                intravisit::walk_foreign_item(v, i);
-            },
-        );
+        self.annotate(i.owner_id.def_id);
+        intravisit::walk_foreign_item(self, i);
     }
 
     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
-        let kind = match &p.kind {
-            // Allow stability attributes on default generic arguments.
-            hir::GenericParamKind::Type { default: Some(_), .. }
-            | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container,
-            _ => AnnotationKind::Prohibited,
-        };
-
-        self.annotate(
-            p.def_id,
-            p.span,
-            None,
-            kind,
-            InheritDeprecation::No,
-            InheritConstStability::No,
-            InheritStability::No,
-            |v| {
-                intravisit::walk_generic_param(v, p);
-            },
-        );
+        self.annotate(p.def_id);
+        intravisit::walk_generic_param(self, p);
     }
 }
 
@@ -597,18 +362,119 @@ struct MissingStabilityAnnotations<'tcx> {
 }
 
 impl<'tcx> MissingStabilityAnnotations<'tcx> {
-    fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
-        let stab = self.tcx.stability().local_stability(def_id);
+    /// Verify that deprecation and stability attributes make sense with one another.
+    #[instrument(level = "trace", skip(self))]
+    fn check_compatible_stability(&self, def_id: LocalDefId) {
+        if !self.tcx.features().staged_api() {
+            return;
+        }
+
+        let depr = self.tcx.lookup_deprecation_entry(def_id);
+        let stab = self.tcx.lookup_stability(def_id);
+        let const_stab = self.tcx.lookup_const_stability(def_id);
+
+        macro_rules! find_attr_span {
+            ($name:ident) => {{
+                let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
+                attrs::find_attr!(attrs, AttributeKind::$name { span, .. } => *span)
+            }}
+        }
+
+        if stab.is_none()
+            && depr.map_or(false, |d| d.attr.is_since_rustc_version())
+            && let Some(span) = find_attr_span!(Deprecation)
+        {
+            self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span });
+        }
+
+        if let Some(stab) = stab {
+            // Error if prohibited, or can't inherit anything from a container.
+            let kind = annotation_kind(self.tcx, def_id);
+            if kind == AnnotationKind::Prohibited
+                || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some())
+            {
+                if let Some(span) = find_attr_span!(Stability) {
+                    let item_sp = self.tcx.def_span(def_id);
+                    self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
+                }
+            }
+
+            // Check if deprecated_since < stable_since. If it is,
+            // this is *almost surely* an accident.
+            if let Some(depr) = depr
+                && let DeprecatedSince::RustcVersion(dep_since) = depr.attr.since
+                && let attrs::StabilityLevel::Stable { since: stab_since, .. } = stab.level
+                && let Some(span) = find_attr_span!(Stability)
+            {
+                let item_sp = self.tcx.def_span(def_id);
+                match stab_since {
+                    StableSince::Current => {
+                        self.tcx
+                            .dcx()
+                            .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
+                    }
+                    StableSince::Version(stab_since) => {
+                        if dep_since < stab_since {
+                            self.tcx
+                                .dcx()
+                                .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
+                        }
+                    }
+                    StableSince::Err(_) => {
+                        // An error already reported. Assume the unparseable stabilization
+                        // version is older than the deprecation version.
+                    }
+                }
+            }
+        }
+
+        // If the current node is a function with const stability attributes (directly given or
+        // implied), check if the function/method is const or the parent impl block is const.
+        let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig();
+        if let Some(fn_sig) = fn_sig
+            && !fn_sig.header.is_const()
+            && const_stab.is_some()
+            && find_attr_span!(ConstStability).is_some()
+        {
+            self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
+        }
+
+        // If this is marked const *stable*, it must also be regular-stable.
+        if let Some(const_stab) = const_stab
+            && let Some(fn_sig) = fn_sig
+            && const_stab.is_const_stable()
+            && !stab.is_some_and(|s| s.is_stable())
+            && let Some(const_span) = find_attr_span!(ConstStability)
+        {
+            self.tcx
+                .dcx()
+                .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
+        }
+
+        if let Some(stab) = &const_stab
+            && stab.is_const_stable()
+            && stab.const_stable_indirect
+            && let Some(span) = find_attr_span!(ConstStability)
+        {
+            self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span });
+        }
+    }
+
+    #[instrument(level = "debug", skip(self))]
+    fn check_missing_stability(&self, def_id: LocalDefId) {
+        let stab = self.tcx.lookup_stability(def_id);
+        self.tcx.ensure_ok().lookup_const_stability(def_id);
         if !self.tcx.sess.is_test_crate()
             && stab.is_none()
             && self.effective_visibilities.is_reachable(def_id)
         {
             let descr = self.tcx.def_descr(def_id.to_def_id());
+            let span = self.tcx.def_span(def_id);
             self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr });
         }
     }
 
-    fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
+    fn check_missing_const_stability(&self, def_id: LocalDefId) {
         let is_const = self.tcx.is_const_fn(def_id.to_def_id())
             || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
                 && self.tcx.is_const_trait(def_id.to_def_id()));
@@ -618,6 +484,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
             && self.effective_visibilities.is_reachable(def_id)
             && self.tcx.lookup_const_stability(def_id).is_none()
         {
+            let span = self.tcx.def_span(def_id);
             let descr = self.tcx.def_descr(def_id.to_def_id());
             self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
         }
@@ -632,6 +499,8 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
     }
 
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
+        self.check_compatible_stability(i.owner_id.def_id);
+
         // Inherent impls and foreign modules serve only as containers for other items,
         // they don't have their own stability. They still can be annotated as unstable
         // and propagate this instability to children, but this annotation is completely
@@ -641,119 +510,97 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
             hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
                 | hir::ItemKind::ForeignMod { .. }
         ) {
-            self.check_missing_stability(i.owner_id.def_id, i.span);
+            self.check_missing_stability(i.owner_id.def_id);
         }
 
         // Ensure stable `const fn` have a const stability attribute.
-        self.check_missing_const_stability(i.owner_id.def_id, i.span);
+        self.check_missing_const_stability(i.owner_id.def_id);
 
         intravisit::walk_item(self, i)
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        self.check_missing_stability(ti.owner_id.def_id, ti.span);
+        self.check_compatible_stability(ti.owner_id.def_id);
+        self.check_missing_stability(ti.owner_id.def_id);
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
+        self.check_compatible_stability(ii.owner_id.def_id);
         let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id());
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
-            self.check_missing_stability(ii.owner_id.def_id, ii.span);
-            self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
+            self.check_missing_stability(ii.owner_id.def_id);
+            self.check_missing_const_stability(ii.owner_id.def_id);
         }
         intravisit::walk_impl_item(self, ii);
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
-        self.check_missing_stability(var.def_id, var.span);
+        self.check_compatible_stability(var.def_id);
+        self.check_missing_stability(var.def_id);
         if let Some(ctor_def_id) = var.data.ctor_def_id() {
-            self.check_missing_stability(ctor_def_id, var.span);
+            self.check_missing_stability(ctor_def_id);
         }
         intravisit::walk_variant(self, var);
     }
 
     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
-        self.check_missing_stability(s.def_id, s.span);
+        self.check_compatible_stability(s.def_id);
+        self.check_missing_stability(s.def_id);
         intravisit::walk_field_def(self, s);
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
-        self.check_missing_stability(i.owner_id.def_id, i.span);
+        self.check_compatible_stability(i.owner_id.def_id);
+        self.check_missing_stability(i.owner_id.def_id);
         intravisit::walk_foreign_item(self, i);
     }
-    // Note that we don't need to `check_missing_stability` for default generic parameters,
-    // as we assume that any default generic parameters without attributes are automatically
-    // stable (assuming they have not inherited instability from their parent).
-}
 
-fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
-    let mut index = Index {
-        stab_map: Default::default(),
-        const_stab_map: Default::default(),
-        default_body_stab_map: Default::default(),
-        depr_map: Default::default(),
-        implications: Default::default(),
-    };
-
-    {
-        let mut annotator = Annotator {
-            tcx,
-            index: &mut index,
-            parent_stab: None,
-            parent_const_stab: None,
-            parent_depr: None,
-            in_trait_impl: false,
-        };
-
-        // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
-        // a parent stability annotation which indicates that this is private
-        // with the `rustc_private` feature. This is intended for use when
-        // compiling `librustc_*` crates themselves so we can leverage crates.io
-        // while maintaining the invariant that all sysroot crates are unstable
-        // by default and are unable to be used.
-        if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
-            let stability = Stability {
-                level: attrs::StabilityLevel::Unstable {
-                    reason: UnstableReason::Default,
-                    issue: NonZero::new(27812),
-                    is_soft: false,
-                    implied_by: None,
-                    old_name: None,
-                },
-                feature: sym::rustc_private,
-            };
-            annotator.parent_stab = Some(stability);
-        }
-
-        annotator.annotate(
-            CRATE_DEF_ID,
-            tcx.hir_span(CRATE_HIR_ID),
-            None,
-            AnnotationKind::Required,
-            InheritDeprecation::Yes,
-            InheritConstStability::No,
-            InheritStability::No,
-            |v| tcx.hir_walk_toplevel_module(v),
-        );
+    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
+        self.check_compatible_stability(p.def_id);
+        // Note that we don't need to `check_missing_stability` for default generic parameters,
+        // as we assume that any default generic parameters without attributes are automatically
+        // stable (assuming they have not inherited instability from their parent).
+        intravisit::walk_generic_param(self, p);
     }
-    index
+}
+
+fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap<Symbol, Symbol> {
+    let mut annotator = Annotator { tcx, implications: Default::default() };
+    annotator.annotate(CRATE_DEF_ID);
+    tcx.hir_walk_toplevel_module(&mut annotator);
+    annotator.implications
 }
 
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
     tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
+
+    let is_staged_api =
+        tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
+    if is_staged_api {
+        let effective_visibilities = &tcx.effective_visibilities(());
+        let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
+        if module_def_id.is_top_level_module() {
+            missing.check_missing_stability(CRATE_DEF_ID);
+        }
+        tcx.hir_visit_item_likes_in_module(module_def_id, &mut missing);
+    }
+
+    if module_def_id.is_top_level_module() {
+        check_unused_or_stable_features(tcx)
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         check_mod_unstable_api_usage,
-        stability_index,
-        stability_implications: |tcx, _| tcx.stability().implications.clone(),
-        lookup_stability: |tcx, id| tcx.stability().local_stability(id),
-        lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id),
-        lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id),
-        lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id),
+        stability_implications,
+        lookup_stability,
+        lookup_const_stability,
+        lookup_default_body_stability,
+        lookup_deprecation_entry,
         ..*providers
     };
 }
@@ -802,12 +649,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
                     let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
 
+                    let unstable_feature_stab =
+                        find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i)
+                            .map(|i| i.as_slice())
+                            .unwrap_or_default();
+
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
                     // it will have no effect.
                     // See: https://github.com/rust-lang/rust/issues/55436
+                    //
+                    // The exception is when there are both  #[unstable_feature_bound(..)] and
+                    //  #![unstable(feature = "..", issue = "..")] that have the same symbol because
+                    // that can effectively mark an impl as unstable.
+                    //
+                    // For example:
+                    // ```
+                    // #[unstable_feature_bound(feat_foo)]
+                    // #[unstable(feature = "feat_foo", issue = "none")]
+                    // impl Foo for Bar {}
+                    // ```
                     if let Some((
-                        Stability { level: attrs::StabilityLevel::Unstable { .. }, .. },
+                        Stability { level: attrs::StabilityLevel::Unstable { .. }, feature },
                         span,
                     )) = stab
                     {
@@ -815,9 +678,21 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                         c.visit_ty_unambig(self_ty);
                         c.visit_trait_ref(t);
 
+                        // Skip the lint if the impl is marked as unstable using
+                        // #[unstable_feature_bound(..)]
+                        let mut unstable_feature_bound_in_effect = false;
+                        for (unstable_bound_feat_name, _) in unstable_feature_stab {
+                            if *unstable_bound_feat_name == feature {
+                                unstable_feature_bound_in_effect = true;
+                            }
+                        }
+
                         // do not lint when the trait isn't resolved, since resolution error should
                         // be fixed first
-                        if t.path.res != Res::Err && c.fully_stable {
+                        if t.path.res != Res::Err
+                            && c.fully_stable
+                            && !unstable_feature_bound_in_effect
+                        {
                             self.tcx.emit_node_span_lint(
                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
                                 item.hir_id(),
@@ -1030,7 +905,7 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     };
     let def_id = owner.def_id;
 
-    let Some(stab) = tcx.stability().local_stability(def_id) else {
+    let Some(stab) = tcx.lookup_stability(def_id) else {
         return false;
     };
 
@@ -1099,16 +974,9 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
 /// Given the list of enabled features that were not language features (i.e., that
 /// were expected to be library features), and the list of features used from
 /// libraries, identify activated features that don't exist and error about them.
+// This is `pub` for rustdoc. rustc should call it through `check_mod_unstable_api_usage`.
 pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
-    let is_staged_api =
-        tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
-    if is_staged_api {
-        let effective_visibilities = &tcx.effective_visibilities(());
-        let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
-        missing.check_missing_stability(CRATE_DEF_ID, tcx.hir_span(CRATE_HIR_ID));
-        tcx.hir_walk_toplevel_module(&mut missing);
-        tcx.hir_visit_all_item_likes_in_crate(&mut missing);
-    }
+    let _prof_timer = tcx.sess.timer("unused_lib_feature_checking");
 
     let enabled_lang_features = tcx.features().enabled_lang_features();
     let mut lang_features = UnordSet::default();
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ab2433234aa..9dd80bc9964 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -156,6 +156,7 @@ where
             }
             ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
             ty::ClauseKind::WellFormed(term) => term.visit_with(self),
+            ty::ClauseKind::UnstableFeature(_) => V::Result::output(),
         }
     }
 
@@ -1623,6 +1624,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
                 self.check(def_id, item_visibility, effective_vis).generics().predicates();
 
                 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
+                    if assoc_item.is_impl_trait_in_trait() {
+                        continue;
+                    }
+
                     self.check_assoc_item(assoc_item, item_visibility, effective_vis);
 
                     if assoc_item.is_type() {
@@ -1735,6 +1740,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
                 check.ty().trait_ref();
 
                 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
+                    if assoc_item.is_impl_trait_in_trait() {
+                        continue;
+                    }
+
                     let impl_item_vis = if !of_trait {
                         min(tcx.local_visibility(assoc_item.def_id.expect_local()), impl_vis, tcx)
                     } else {
diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml
index 748fa944e28..762acf9a1eb 100644
--- a/compiler/rustc_proc_macro/Cargo.toml
+++ b/compiler/rustc_proc_macro/Cargo.toml
@@ -15,7 +15,7 @@ test = false
 doctest = false
 
 [dependencies]
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 
 [features]
 rustc-dep-of-std = []
diff --git a/compiler/rustc_public/src/rustc_internal/mod.rs b/compiler/rustc_public/src/rustc_internal/mod.rs
index 5d7c8256d5b..01354fc7bd4 100644
--- a/compiler/rustc_public/src/rustc_internal/mod.rs
+++ b/compiler/rustc_public/src/rustc_internal/mod.rs
@@ -144,10 +144,10 @@ where
 #[macro_export]
 macro_rules! run {
     ($args:expr, $callback_fn:ident) => {
-        run_driver!($args, || $callback_fn())
+        $crate::run_driver!($args, || $callback_fn())
     };
     ($args:expr, $callback:expr) => {
-        run_driver!($args, $callback)
+        $crate::run_driver!($args, $callback)
     };
 }
 
@@ -158,10 +158,10 @@ macro_rules! run {
 #[macro_export]
 macro_rules! run_with_tcx {
     ($args:expr, $callback_fn:ident) => {
-        run_driver!($args, |tcx| $callback_fn(tcx), with_tcx)
+        $crate::run_driver!($args, |tcx| $callback_fn(tcx), with_tcx)
     };
     ($args:expr, $callback:expr) => {
-        run_driver!($args, $callback, with_tcx)
+        $crate::run_driver!($args, $callback, with_tcx)
     };
 }
 
@@ -191,11 +191,11 @@ macro_rules! run_driver {
         use rustc_public::CompilerError;
         use std::ops::ControlFlow;
 
-        pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>>
+        pub struct StableMir<B = (), C = (), F = fn($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>>
         where
             B: Send,
             C: Send,
-            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
+            F: FnOnce($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             callback: Option<F>,
             result: Option<ControlFlow<B, C>>,
@@ -205,7 +205,7 @@ macro_rules! run_driver {
         where
             B: Send,
             C: Send,
-            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
+            F: FnOnce($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             /// Creates a new `StableMir` instance, with given test_function and arguments.
             pub fn new(callback: F) -> Self {
@@ -240,7 +240,7 @@ macro_rules! run_driver {
         where
             B: Send,
             C: Send,
-            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
+            F: FnOnce($($crate::optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             /// Called after analysis. Return value instructs the compiler whether to
             /// continue the compilation afterwards (defaults to `Compilation::Continue`)
@@ -251,7 +251,7 @@ macro_rules! run_driver {
             ) -> Compilation {
                 if let Some(callback) = self.callback.take() {
                     rustc_internal::run(tcx, || {
-                        self.result = Some(callback($(optional!($with_tcx tcx))?));
+                        self.result = Some(callback($($crate::optional!($with_tcx tcx))?));
                     })
                     .unwrap();
                     if self.result.as_ref().is_some_and(|val| val.is_continue()) {
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index 75c29788787..6b226b8a24d 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -764,6 +764,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
             ClauseKind::HostEffect(..) => {
                 todo!()
             }
+            ClauseKind::UnstableFeature(_) => {
+                todo!()
+            }
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 5a1be618cee..737577baa7a 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -85,7 +85,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
     /// but they cannot use def-site hygiene, so the assumption holds
     /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
-    pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'ra> {
+    pub(crate) fn get_nearest_non_block_module(&self, mut def_id: DefId) -> Module<'ra> {
         loop {
             match self.get_module(def_id) {
                 Some(module) => return module,
@@ -94,44 +94,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'ra> {
+    pub(crate) fn expect_module(&self, def_id: DefId) -> Module<'ra> {
         self.get_module(def_id).expect("argument `DefId` is not a module")
     }
 
     /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum,
     /// or trait), then this function returns that module's resolver representation, otherwise it
     /// returns `None`.
-    pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'ra>> {
-        if let module @ Some(..) = self.module_map.get(&def_id) {
-            return module.copied();
-        }
+    pub(crate) fn get_module(&self, def_id: DefId) -> Option<Module<'ra>> {
+        match def_id.as_local() {
+            Some(local_def_id) => self.local_module_map.get(&local_def_id).copied(),
+            None => {
+                if let module @ Some(..) = self.extern_module_map.borrow().get(&def_id) {
+                    return module.copied();
+                }
 
-        if !def_id.is_local() {
-            // Query `def_kind` is not used because query system overhead is too expensive here.
-            let def_kind = self.cstore().def_kind_untracked(def_id);
-            if def_kind.is_module_like() {
-                let parent = self
-                    .tcx
-                    .opt_parent(def_id)
-                    .map(|parent_id| self.get_nearest_non_block_module(parent_id));
-                // Query `expn_that_defined` is not used because
-                // hashing spans in its result is expensive.
-                let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
-                return Some(self.new_module(
-                    parent,
-                    ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))),
-                    expn_id,
-                    self.def_span(def_id),
-                    // FIXME: Account for `#[no_implicit_prelude]` attributes.
-                    parent.is_some_and(|module| module.no_implicit_prelude),
-                ));
+                // Query `def_kind` is not used because query system overhead is too expensive here.
+                let def_kind = self.cstore().def_kind_untracked(def_id);
+                if def_kind.is_module_like() {
+                    let parent = self
+                        .tcx
+                        .opt_parent(def_id)
+                        .map(|parent_id| self.get_nearest_non_block_module(parent_id));
+                    // Query `expn_that_defined` is not used because
+                    // hashing spans in its result is expensive.
+                    let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
+                    return Some(self.new_extern_module(
+                        parent,
+                        ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))),
+                        expn_id,
+                        self.def_span(def_id),
+                        // FIXME: Account for `#[no_implicit_prelude]` attributes.
+                        parent.is_some_and(|module| module.no_implicit_prelude),
+                    ));
+                }
+
+                None
             }
         }
-
-        None
     }
 
-    pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> {
+    pub(crate) fn expn_def_scope(&self, expn_id: ExpnId) -> Module<'ra> {
         match expn_id.expn_data().macro_def_id {
             Some(def_id) => self.macro_def_scope(def_id),
             None => expn_id
@@ -141,7 +144,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'ra> {
+    pub(crate) fn macro_def_scope(&self, def_id: DefId) -> Module<'ra> {
         if let Some(id) = def_id.as_local() {
             self.local_macro_def_scopes[&id]
         } else {
@@ -403,7 +406,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         self.r.field_visibility_spans.insert(def_id, field_vis);
     }
 
-    fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
+    fn block_needs_anonymous_module(&self, block: &Block) -> bool {
         // If any statements are items, we need to create an anonymous module
         block
             .stmts
@@ -758,7 +761,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
                     self.r.mods_with_parse_errors.insert(def_id);
                 }
-                self.parent_scope.module = self.r.new_module(
+                self.parent_scope.module = self.r.new_local_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, Some(ident.name)),
                     expansion.to_expn_id(),
@@ -790,7 +793,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => {
                 self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);
 
-                self.parent_scope.module = self.r.new_module(
+                self.parent_scope.module = self.r.new_local_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, Some(ident.name)),
                     expansion.to_expn_id(),
@@ -894,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())
@@ -986,7 +992,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         let parent = self.parent_scope.module;
         let expansion = self.parent_scope.expansion;
         if self.block_needs_anonymous_module(block) {
-            let module = self.r.new_module(
+            let module = self.r.new_local_module(
                 Some(parent),
                 ModuleKind::Block,
                 expansion.to_expn_id(),
@@ -1118,7 +1124,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
     }
 
     /// Returns `true` if this attribute list contains `macro_use`.
-    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+    fn contains_macro_use(&self, attrs: &[ast::Attribute]) -> bool {
         for attr in attrs {
             if attr.has_name(sym::macro_escape) {
                 let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 781e2ce9704..7d51fef28d3 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -2,7 +2,7 @@ use std::mem;
 
 use rustc_ast::visit::FnKind;
 use rustc_ast::*;
-use rustc_attr_parsing::{AttributeParser, Early, OmitDoc};
+use rustc_attr_parsing::{AttributeParser, Early, OmitDoc, ShouldEmit};
 use rustc_expand::expand::AstFragment;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
@@ -132,7 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                     &self.resolver.tcx.sess,
                     self.resolver.tcx.features(),
                     Vec::new(),
-                    Early { emit_errors: false },
+                    Early { emit_errors: ShouldEmit::Nothing },
                 );
                 let attrs = parser.parse_attribute_list(
                     &i.attrs,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 11e4a729ae2..d72fbc189e7 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1,6 +1,8 @@
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path};
+use rustc_ast::{
+    self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents,
+};
 use rustc_ast_pretty::pprust;
 use rustc_attr_data_structures::{
     self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr,
@@ -1423,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;
                 };
@@ -2018,7 +2021,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             }
         }
 
-        let mut sugg_paths = vec![];
+        let mut sugg_paths: Vec<(Vec<Ident>, bool)> = vec![];
         if let Some(mut def_id) = res.opt_def_id() {
             // We can't use `def_path_str` in resolve.
             let mut path = vec![def_id];
@@ -2031,16 +2034,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
             }
             // We will only suggest importing directly if it is accessible through that path.
-            let path_names: Option<Vec<String>> = path
+            let path_names: Option<Vec<Ident>> = path
                 .iter()
                 .rev()
                 .map(|def_id| {
-                    self.tcx.opt_item_name(*def_id).map(|n| {
-                        if def_id.is_top_level_module() {
-                            "crate".to_string()
+                    self.tcx.opt_item_name(*def_id).map(|name| {
+                        Ident::with_dummy_span(if def_id.is_top_level_module() {
+                            kw::Crate
                         } else {
-                            n.to_string()
-                        }
+                            name
+                        })
                     })
                 })
                 .collect();
@@ -2084,13 +2087,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             match binding.kind {
                 NameBindingKind::Import { import, .. } => {
                     for segment in import.module_path.iter().skip(1) {
-                        path.push(segment.ident.to_string());
+                        path.push(segment.ident);
                     }
                     sugg_paths.push((
-                        path.iter()
-                            .cloned()
-                            .chain(vec![ident.to_string()].into_iter())
-                            .collect::<Vec<_>>(),
+                        path.iter().cloned().chain(std::iter::once(ident)).collect::<Vec<_>>(),
                         true, // re-export
                     ));
                 }
@@ -2126,7 +2126,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             err.subdiagnostic(note);
         }
         // We prioritize shorter paths, non-core imports and direct imports over the alternatives.
-        sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
+        sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport));
         for (sugg, reexport) in sugg_paths {
             if not_publicly_reexported {
                 break;
@@ -2136,7 +2136,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 // `tests/ui/imports/issue-55884-2.rs`
                 continue;
             }
-            let path = sugg.join("::");
+            let path = join_path_idents(sugg);
             let sugg = if reexport {
                 errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
             } else {
@@ -2150,7 +2150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     pub(crate) fn find_similarly_named_module_or_crate(
-        &mut self,
+        &self,
         ident: Symbol,
         current_module: Module<'ra>,
     ) -> Option<Symbol> {
@@ -2159,7 +2159,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             .keys()
             .map(|ident| ident.name)
             .chain(
-                self.module_map
+                self.local_module_map
+                    .iter()
+                    .filter(|(_, module)| {
+                        current_module.is_ancestor_of(**module) && current_module != **module
+                    })
+                    .flat_map(|(_, module)| module.kind.name()),
+            )
+            .chain(
+                self.extern_module_map
+                    .borrow()
                     .iter()
                     .filter(|(_, module)| {
                         current_module.is_ancestor_of(**module) && current_module != **module
@@ -2435,7 +2444,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     fn undeclared_module_suggest_declare(
-        &mut self,
+        &self,
         ident: Ident,
         path: std::path::PathBuf,
     ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
@@ -2450,7 +2459,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         ))
     }
 
-    fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
+    fn undeclared_module_exists(&self, ident: Ident) -> Option<std::path::PathBuf> {
         let map = self.tcx.sess.source_map();
 
         let src = map.span_to_filename(ident.span).into_local_path()?;
@@ -2809,24 +2818,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     return cached;
                 }
                 visited.insert(parent_module, false);
-                let res = r.module_map.get(&parent_module).is_some_and(|m| {
-                    for importer in m.glob_importers.borrow().iter() {
-                        if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
+                let m = r.expect_module(parent_module);
+                let mut res = false;
+                for importer in m.glob_importers.borrow().iter() {
+                    if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() {
+                        if next_parent_module == module
+                            || comes_from_same_module_for_glob(
+                                r,
+                                next_parent_module,
+                                module,
+                                visited,
+                            )
                         {
-                            if next_parent_module == module
-                                || comes_from_same_module_for_glob(
-                                    r,
-                                    next_parent_module,
-                                    module,
-                                    visited,
-                                )
-                            {
-                                return true;
-                            }
+                            res = true;
+                            break;
                         }
                     }
-                    false
-                });
+                }
                 visited.insert(parent_module, res);
                 res
             }
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 5de80de3f8d..34d1e9552fd 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -38,11 +38,11 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
 }
 
 impl Resolver<'_, '_> {
-    fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
+    fn nearest_normal_mod(&self, def_id: LocalDefId) -> LocalDefId {
         self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
     }
 
-    fn private_vis_import(&mut self, binding: NameBinding<'_>) -> Visibility {
+    fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility {
         let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
         Visibility::Restricted(
             import
@@ -52,7 +52,7 @@ impl Resolver<'_, '_> {
         )
     }
 
-    fn private_vis_def(&mut self, def_id: LocalDefId) -> Visibility {
+    fn private_vis_def(&self, def_id: LocalDefId) -> Visibility {
         // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
         let normal_mod_id = self.nearest_normal_mod(def_id);
         if normal_mod_id == def_id {
@@ -113,8 +113,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
     /// Update effective visibilities of bindings in the given module,
     /// including their whole reexport chains.
     fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
-        assert!(self.r.module_map.contains_key(&module_id.to_def_id()));
-        let module = self.r.get_module(module_id.to_def_id()).unwrap();
+        let module = self.r.expect_module(module_id.to_def_id());
         let resolutions = self.r.resolutions(module);
 
         for (_, name_resolution) in resolutions.borrow().iter() {
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 84d66c15f00..34941398a2b 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -219,7 +219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     fn hygienic_lexical_parent(
-        &mut self,
+        &self,
         module: Module<'ra>,
         ctxt: &mut SyntaxContext,
         derive_fallback_lint_id: Option<NodeId>,
@@ -841,7 +841,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 if ns == TypeNS {
                     if ident.name == kw::Crate || ident.name == kw::DollarCrate {
                         let module = self.resolve_crate_root(ident);
-                        return Ok(self.module_self_bindings[&module]);
+                        return Ok(module.self_binding.unwrap());
                     } else if ident.name == kw::Super || ident.name == kw::SelfLower {
                         // FIXME: Implement these with renaming requirements so that e.g.
                         // `use super;` doesn't work, but `use super as name;` does.
@@ -885,7 +885,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             );
         }
 
-        let check_usable = |this: &mut Self, binding: NameBinding<'ra>| {
+        let check_usable = |this: &Self, binding: NameBinding<'ra>| {
             let usable = this.is_accessible_from(binding.vis, parent_scope.module);
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
         };
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 9a031ee03e0..0a4c25b0eb0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -15,8 +15,8 @@ use rustc_middle::span_bug;
 use rustc_middle::ty::Visibility;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
-    AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE,
-    REDUNDANT_IMPORTS, UNUSED_IMPORTS,
+    AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS,
+    PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -456,7 +456,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         f: F,
     ) -> T
     where
-        F: FnOnce(&mut Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T,
+        F: FnOnce(&Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T,
     {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
@@ -635,10 +635,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    pub(crate) fn check_hidden_glob_reexports(
-        &mut self,
-        exported_ambiguities: FxHashSet<NameBinding<'ra>>,
-    ) {
+    pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet<NameBinding<'ra>>) {
         for module in self.arenas.local_modules().iter() {
             for (key, resolution) in self.resolutions(*module).borrow().iter() {
                 let resolution = resolution.borrow();
@@ -697,6 +694,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         }
                     }
                 }
+
+                if let NameBindingKind::Import { import, .. } = binding.kind
+                    && let Some(binding_id) = import.id()
+                    && let import_def_id = self.local_def_id(binding_id)
+                    && self.effective_visibilities.is_exported(import_def_id)
+                    && let Res::Def(reexported_kind, reexported_def_id) = binding.res()
+                    && !matches!(reexported_kind, DefKind::Ctor(..))
+                    && !reexported_def_id.is_local()
+                    && self.tcx.is_private_dep(reexported_def_id.krate)
+                {
+                    self.lint_buffer.buffer_lint(
+                        EXPORTED_PRIVATE_DEPENDENCIES,
+                        binding_id,
+                        binding.span,
+                        BuiltinLintDiag::ReexportPrivateDependency {
+                            kind: binding.res().descr().to_string(),
+                            name: key.ident.name.to_string(),
+                            krate: self.tcx.crate_name(reexported_def_id.krate),
+                        },
+                    );
+                }
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3ef98100d09..a3a770502de 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2491,7 +2491,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
 
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
     /// label and reports an error if the label is not found or is unreachable.
-    fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> {
+    fn resolve_label(&self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> {
         let mut suggestion = None;
 
         for i in (0..self.label_ribs.len()).rev() {
@@ -2899,9 +2899,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 }
 
                 if param.ident.name == kw::UnderscoreLifetime {
+                    // To avoid emitting two similar errors,
+                    // we need to check if the span is a raw underscore lifetime, see issue #143152
+                    let is_raw_underscore_lifetime = self
+                        .r
+                        .tcx
+                        .sess
+                        .psess
+                        .raw_identifier_spans
+                        .iter()
+                        .any(|span| span == param.span());
+
                     self.r
                         .dcx()
-                        .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
+                        .create_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span })
+                        .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 a4601cb44eb..69095942f52 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -926,7 +926,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     continue;
                 };
                 if let Res::Def(DefKind::Mod, module) = res.expect_full_res()
-                    && let Some(module) = self.r.get_module(module)
+                    && let module = self.r.expect_module(module)
                     && let item = path[idx + 1].ident
                     && let Some(did) = find_doc_alias_name(self.r, module, item.name)
                 {
@@ -939,7 +939,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn suggest_trait_and_bounds(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         source: PathSource<'_, '_, '_>,
         res: Option<Res>,
@@ -1140,7 +1140,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
     /// Emit special messages for unresolved `Self` and `self`.
     fn suggest_self_ty(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         source: PathSource<'_, '_, '_>,
         path: &[Segment],
@@ -1256,7 +1256,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn detect_missing_binding_available_from_pattern(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
@@ -1302,11 +1302,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         }
     }
 
-    fn suggest_at_operator_in_slice_pat_with_range(
-        &mut self,
-        err: &mut Diag<'_>,
-        path: &[Segment],
-    ) {
+    fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) {
         let Some(pat) = self.diag_metadata.current_pat else { return };
         let (bound, side, range) = match &pat.kind {
             ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),
@@ -1367,7 +1363,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn explain_functions_in_pattern(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         res: Option<Res>,
         source: PathSource<'_, '_, '_>,
@@ -1379,7 +1375,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn suggest_changing_type_to_const_param(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         res: Option<Res>,
         source: PathSource<'_, '_, '_>,
@@ -1429,7 +1425,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     fn suggest_pattern_match_with_let(
-        &mut self,
+        &self,
         err: &mut Diag<'_>,
         source: PathSource<'_, '_, '_>,
         span: Span,
@@ -1485,7 +1481,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     }
 
     /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
-    fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diag<'_>) -> bool {
+    fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {
         // Detect that we are actually in a `where` predicate.
         let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate {
             kind:
@@ -1633,7 +1629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         let ns = source.namespace();
         let is_expected = &|res| source.is_expected(res);
 
-        let path_sep = |this: &mut Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| {
+        let path_sep = |this: &Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| {
             const MESSAGE: &str = "use the path separator to refer to an item";
 
             let (lhs_span, rhs_span) = match &expr.kind {
@@ -2489,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());
@@ -2531,16 +2528,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     // FIXME: this is not totally accurate, but mostly works
                     suggestion.candidate != following_seg.ident.name
                 }
-                Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
-                    || false,
-                    |module| {
-                        self.r
-                            .resolutions(module)
-                            .borrow()
-                            .iter()
-                            .any(|(key, _)| key.ident.name == following_seg.ident.name)
-                    },
-                ),
+                Res::Def(DefKind::Mod, def_id) => {
+                    let module = self.r.expect_module(def_id);
+                    self.r
+                        .resolutions(module)
+                        .borrow()
+                        .iter()
+                        .any(|(key, _)| key.ident.name == following_seg.ident.name)
+                }
                 _ => true,
             });
         }
@@ -2589,7 +2584,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
     // try to give a suggestion for this pattern: `name = blah`, which is common in other languages
     // suggest `let name = blah` to introduce a new binding
-    fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool {
+    fn let_binding_suggestion(&self, err: &mut Diag<'_>, ident_span: Span) -> bool {
         if ident_span.from_expansion() {
             return false;
         }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b0b29bc2eae..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;
@@ -585,6 +585,10 @@ struct ModuleData<'ra> {
     span: Span,
 
     expansion: ExpnId,
+
+    /// Binding for implicitly declared names that come with a module,
+    /// like `self` (not yet used), or `crate`/`$crate` (for root modules).
+    self_binding: Option<NameBinding<'ra>>,
 }
 
 /// All modules are unique and allocated on a same arena,
@@ -613,6 +617,7 @@ impl<'ra> ModuleData<'ra> {
         expansion: ExpnId,
         span: Span,
         no_implicit_prelude: bool,
+        self_binding: Option<NameBinding<'ra>>,
     ) -> Self {
         let is_foreign = match kind {
             ModuleKind::Def(_, def_id, _) => !def_id.is_local(),
@@ -630,6 +635,7 @@ impl<'ra> ModuleData<'ra> {
             traits: RefCell::new(None),
             span,
             expansion,
+            self_binding,
         }
     }
 }
@@ -1075,7 +1081,10 @@ pub struct Resolver<'ra, 'tcx> {
     /// some AST passes can generate identifiers that only resolve to local or
     /// lang items.
     empty_module: Module<'ra>,
-    module_map: FxIndexMap<DefId, Module<'ra>>,
+    /// Eagerly populated map of all local non-block modules.
+    local_module_map: FxIndexMap<LocalDefId, Module<'ra>>,
+    /// Lazily populated cache of modules loaded from external crates.
+    extern_module_map: RefCell<FxIndexMap<DefId, Module<'ra>>>,
     binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>,
 
     underscore_disambiguator: u32,
@@ -1101,17 +1110,13 @@ 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>>,
-    /// Binding for implicitly declared names that come with a module,
-    /// like `self` (not yet used), or `crate`/`$crate` (for root modules).
-    module_self_bindings: FxHashMap<Module<'ra>, NameBinding<'ra>>,
-
-    used_extern_options: FxHashSet<Symbol>,
     macro_names: FxHashSet<Ident>,
     builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind>,
     registered_tools: &'tcx RegisteredTools,
     macro_use_prelude: FxIndexMap<Symbol, NameBinding<'ra>>,
+    /// Eagerly populated map of all local macro definitions.
     local_macro_map: FxHashMap<LocalDefId, &'ra MacroData>,
-    /// Lazily populated cache of macros loaded from external crates.
+    /// Lazily populated cache of macro definitions loaded from external crates.
     extern_macro_map: RefCell<FxHashMap<DefId, &'ra MacroData>>,
     dummy_ext_bang: Arc<SyntaxExtension>,
     dummy_ext_derive: Arc<SyntaxExtension>,
@@ -1263,26 +1268,25 @@ impl<'ra> ResolverArenas<'ra> {
         expn_id: ExpnId,
         span: Span,
         no_implicit_prelude: bool,
-        module_map: &mut FxIndexMap<DefId, Module<'ra>>,
-        module_self_bindings: &mut FxHashMap<Module<'ra>, NameBinding<'ra>>,
     ) -> Module<'ra> {
+        let (def_id, self_binding) = match kind {
+            ModuleKind::Def(def_kind, def_id, _) => (
+                Some(def_id),
+                Some(self.new_pub_res_binding(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)),
+            ),
+            ModuleKind::Block => (None, None),
+        };
         let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new(
             parent,
             kind,
             expn_id,
             span,
             no_implicit_prelude,
+            self_binding,
         ))));
-        let def_id = module.opt_def_id();
         if def_id.is_none_or(|def_id| def_id.is_local()) {
             self.local_modules.borrow_mut().push(module);
         }
-        if let Some(def_id) = def_id {
-            module_map.insert(def_id, module);
-            let res = module.res().unwrap();
-            let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT);
-            module_self_bindings.insert(module, binding);
-        }
         module
     }
     fn local_modules(&'ra self) -> std::cell::Ref<'ra, Vec<Module<'ra>>> {
@@ -1423,25 +1427,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         arenas: &'ra ResolverArenas<'ra>,
     ) -> Resolver<'ra, 'tcx> {
         let root_def_id = CRATE_DEF_ID.to_def_id();
-        let mut module_map = FxIndexMap::default();
-        let mut module_self_bindings = FxHashMap::default();
+        let mut local_module_map = FxIndexMap::default();
         let graph_root = arenas.new_module(
             None,
             ModuleKind::Def(DefKind::Mod, root_def_id, None),
             ExpnId::root(),
             crate_span,
             attr::contains_name(attrs, sym::no_implicit_prelude),
-            &mut module_map,
-            &mut module_self_bindings,
         );
+        local_module_map.insert(CRATE_DEF_ID, graph_root);
         let empty_module = arenas.new_module(
             None,
             ModuleKind::Def(DefKind::Mod, root_def_id, None),
             ExpnId::root(),
             DUMMY_SP,
             true,
-            &mut Default::default(),
-            &mut Default::default(),
         );
 
         let mut node_id_to_def_id = NodeMap::default();
@@ -1502,7 +1502,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             trait_map: NodeMap::default(),
             underscore_disambiguator: 0,
             empty_module,
-            module_map,
+            local_module_map,
+            extern_module_map: Default::default(),
             block_map: Default::default(),
             binding_parent_modules: FxHashMap::default(),
             ast_transform_scopes: FxHashMap::default(),
@@ -1544,9 +1545,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     (*ident, binding)
                 })
                 .collect(),
-            module_self_bindings,
-
-            used_extern_options: Default::default(),
             macro_names: FxHashSet::default(),
             builtin_macros: Default::default(),
             registered_tools,
@@ -1608,7 +1606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         resolver
     }
 
-    fn new_module(
+    fn new_local_module(
         &mut self,
         parent: Option<Module<'ra>>,
         kind: ModuleKind,
@@ -1616,17 +1614,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         span: Span,
         no_implicit_prelude: bool,
     ) -> Module<'ra> {
-        let module_map = &mut self.module_map;
-        let module_self_bindings = &mut self.module_self_bindings;
-        self.arenas.new_module(
-            parent,
-            kind,
-            expn_id,
-            span,
-            no_implicit_prelude,
-            module_map,
-            module_self_bindings,
-        )
+        let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
+        if let Some(def_id) = module.opt_def_id() {
+            self.local_module_map.insert(def_id.expect_local(), module);
+        }
+        module
+    }
+
+    fn new_extern_module(
+        &self,
+        parent: Option<Module<'ra>>,
+        kind: ModuleKind,
+        expn_id: ExpnId,
+        span: Span,
+        no_implicit_prelude: bool,
+    ) -> Module<'ra> {
+        let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
+        self.extern_module_map.borrow_mut().insert(module.def_id(), module);
+        module
     }
 
     fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData {
@@ -1726,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),
@@ -1773,9 +1774,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
                 EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
             });
-            self.tcx.sess.time("check_hidden_glob_reexports", || {
-                self.check_hidden_glob_reexports(exported_ambiguities)
-            });
+            self.tcx.sess.time("lint_reexports", || self.lint_reexports(exported_ambiguities));
             self.tcx
                 .sess
                 .time("finalize_macro_resolutions", || self.finalize_macro_resolutions(krate));
@@ -1785,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.
@@ -2014,7 +2013,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
-    fn resolve_crate_root(&mut self, ident: Ident) -> Module<'ra> {
+    fn resolve_crate_root(&self, ident: Ident) -> Module<'ra> {
         debug!("resolve_crate_root({:?})", ident);
         let mut ctxt = ident.span.ctxt();
         let mark = if ident.name == kw::DollarCrate {
@@ -2087,7 +2086,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         module
     }
 
-    fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> {
+    fn resolve_self(&self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> {
         let mut module = self.expect_module(module.nearest_parent_mod());
         while module.span.ctxt().normalize_to_macros_2_0() != *ctxt {
             let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark()));
@@ -2151,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);
                     }
@@ -2160,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 c17d74659db..77ef7f56c09 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -170,7 +170,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
         self.invocation_parents[&id].parent_def
     }
 
-    fn resolve_dollar_crates(&mut self) {
+    fn resolve_dollar_crates(&self) {
         hygiene::update_dollar_crate_names(|ctxt| {
             let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
             match self.resolve_crate_root(ident).kind {
@@ -835,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
-        let check_consistency = |this: &mut Self,
+        let check_consistency = |this: &Self,
                                  path: &[Segment],
                                  span,
                                  kind: MacroKind,
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index f61cd1f0adf..24e15ded94f 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -7,6 +7,7 @@ use pulldown_cmark::{
 };
 use rustc_ast as ast;
 use rustc_ast::attr::AttributeExt;
+use rustc_ast::join_path_syms;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::UnordSet;
@@ -259,7 +260,7 @@ pub fn main_body_opts() -> Options {
         | Options::ENABLE_SMART_PUNCTUATION
 }
 
-fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> {
+fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<Symbol, MalformedGenerics> {
     let mut stripped_segment = String::new();
     let mut param_depth = 0;
 
@@ -284,7 +285,7 @@ fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, Malfor
     }
 
     if param_depth == 0 {
-        Ok(stripped_segment)
+        Ok(Symbol::intern(&stripped_segment))
     } else {
         // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>`
         Err(MalformedGenerics::UnbalancedAngleBrackets)
@@ -346,9 +347,8 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
 
     debug!("path_str: {path_str:?}\nstripped segments: {stripped_segments:?}");
 
-    let stripped_path = stripped_segments.join("::");
-
-    if !stripped_path.is_empty() {
+    if !stripped_segments.is_empty() {
+        let stripped_path = join_path_syms(stripped_segments);
         Ok(stripped_path.into())
     } else {
         Err(MalformedGenerics::MissingType)
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index a91e2140fd4..d6215e1de04 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1708,6 +1708,11 @@ impl RustcOptGroup {
             OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
         };
     }
+
+    /// This is for diagnostics-only.
+    pub fn long_name(&self) -> &str {
+        self.long_name
+    }
 }
 
 pub fn make_opt(
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 626262c8442..2bdde2f887a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2256,6 +2256,8 @@ options! {
         environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
     has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "explicitly enable the `cfg(target_thread_local)` directive"),
+    higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED],
+        "allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"),
     hint_mostly_unused: bool = (false, parse_bool, [TRACKED],
         "hint that most of this crate will go unused, to minimize work for uncalled functions"),
     human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 0118cdb1fc2..9097b27b86c 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -205,6 +205,46 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
     }
 }
 
+/// This is only used by unstable_feature_bound as it does not have issue number information for now.
+/// This is basically the same as `feature_err_issue`
+/// but without the feature issue note. If we can do a lookup for issue number from feature name,
+/// then we should directly use `feature_err_issue` for ambiguity error of
+/// `#[unstable_feature_bound]`.
+#[track_caller]
+pub fn feature_err_unstable_feature_bound(
+    sess: &Session,
+    feature: Symbol,
+    span: impl Into<MultiSpan>,
+    explain: impl Into<DiagMessage>,
+) -> Diag<'_> {
+    let span = span.into();
+
+    // Cancel an earlier warning for this same error, if it exists.
+    if let Some(span) = span.primary_span() {
+        if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) {
+            err.cancel()
+        }
+    }
+
+    let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
+
+    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
+    if sess.psess.unstable_features.is_nightly_build() {
+        err.subdiagnostic(FeatureDiagnosticHelp { feature });
+
+        if feature == sym::rustc_attrs {
+            // We're unlikely to stabilize something out of `rustc_attrs`
+            // without at least renaming it, so pointing out how old
+            // the compiler is will do little good.
+        } else if sess.opts.unstable_opts.ui_testing {
+            err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
+        } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
+            err.subdiagnostic(suggestion);
+        }
+    }
+    err
+}
+
 /// Info about a parsing session.
 pub struct ParseSess {
     dcx: DiagCtxt,
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 641bac88ad0..77f01548bca 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -110,6 +110,7 @@ impl DefPathHash {
 
     /// Builds a new [DefPathHash] with the given [StableCrateId] and
     /// `local_hash`, where `local_hash` must be unique within its crate.
+    #[inline]
     pub fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> DefPathHash {
         DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash))
     }
@@ -404,21 +405,21 @@ rustc_data_structures::define_id_collections!(
 impl<CTX: HashStableContext> HashStable<CTX> for DefId {
     #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+        hcx.def_path_hash(*self).hash_stable(hcx, hasher);
     }
 }
 
 impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId {
     #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+        hcx.def_path_hash(self.to_def_id()).local_hash().hash_stable(hcx, hasher);
     }
 }
 
 impl<CTX: HashStableContext> HashStable<CTX> for CrateNum {
     #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+        self.as_def_id().to_stable_hash_key(hcx).stable_crate_id().hash_stable(hcx, hasher);
     }
 }
 
@@ -464,30 +465,36 @@ macro_rules! typed_def_id {
         pub struct $Name(DefId);
 
         impl $Name {
+            #[inline]
             pub const fn new_unchecked(def_id: DefId) -> Self {
                 Self(def_id)
             }
 
+            #[inline]
             pub fn to_def_id(self) -> DefId {
                 self.into()
             }
 
+            #[inline]
             pub fn is_local(self) -> bool {
                 self.0.is_local()
             }
 
+            #[inline]
             pub fn as_local(self) -> Option<$LocalName> {
                 self.0.as_local().map($LocalName::new_unchecked)
             }
         }
 
         impl From<$LocalName> for $Name {
+            #[inline]
             fn from(local: $LocalName) -> Self {
                 Self(local.0.to_def_id())
             }
         }
 
         impl From<$Name> for DefId {
+            #[inline]
             fn from(typed: $Name) -> Self {
                 typed.0
             }
@@ -500,26 +507,31 @@ macro_rules! typed_def_id {
         impl !PartialOrd for $LocalName {}
 
         impl $LocalName {
+            #[inline]
             pub const fn new_unchecked(def_id: LocalDefId) -> Self {
                 Self(def_id)
             }
 
+            #[inline]
             pub fn to_def_id(self) -> DefId {
                 self.0.into()
             }
 
+            #[inline]
             pub fn to_local_def_id(self) -> LocalDefId {
                 self.0
             }
         }
 
         impl From<$LocalName> for LocalDefId {
+            #[inline]
             fn from(typed: $LocalName) -> Self {
                 typed.0
             }
         }
 
         impl From<$LocalName> for DefId {
+            #[inline]
             fn from(typed: $LocalName) -> Self {
                 typed.0.into()
             }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8b12edf426c..d28a73bc139 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -715,6 +715,7 @@ symbols! {
         const_indexing,
         const_let,
         const_loop,
+        const_make_global,
         const_mut_refs,
         const_panic,
         const_panic_fmt,
@@ -839,6 +840,7 @@ symbols! {
         derive,
         derive_coerce_pointee,
         derive_const,
+        derive_const_issue: "118304",
         derive_default_enum,
         derive_smart_pointer,
         destruct,
@@ -2284,6 +2286,7 @@ symbols! {
         unsized_locals,
         unsized_tuple_coercion,
         unstable,
+        unstable_feature_bound,
         unstable_location_reason_default: "this crate is being loaded from the sysroot, an \
                           unstable location; did you mean to load this crate \
                           from crates.io via `Cargo.toml` instead?",
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index a9bf5eae445..6bcb7f6e093 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -180,7 +180,7 @@ fn compute_symbol_name<'tcx>(
 
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
     let attrs = if tcx.def_kind(def_id).has_codegen_attrs() {
-        tcx.codegen_fn_attrs(def_id)
+        &tcx.codegen_instance_attrs(instance.def)
     } else {
         CodegenFnAttrs::EMPTY
     };
diff --git a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs
index f20782cabb8..0d6c6194e26 100644
--- a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs
+++ b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs
@@ -3,7 +3,7 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, Target, TargetMetadata,
 pub(crate) fn target() -> Target {
     Target {
         arch: "amdgpu".into(),
-        data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(),
+        data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(),
         llvm_target: "amdgcn-amd-amdhsa".into(),
         metadata: TargetMetadata {
             description: Some("AMD GPU".into()),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
index fd509503053..f95ce756354 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
@@ -5,7 +5,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
     base.cpu = "mips64r2".into();
-    base.features = "+mips64r2".into();
+    base.features = "+mips64r2,+xgot".into();
     base.max_atomic_width = Some(64);
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
index aa087b1a35a..d42e097b0fd 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
@@ -3,7 +3,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base};
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
     base.cpu = "mips64r2".into();
-    base.features = "+mips64r2".into();
+    base.features = "+mips64r2,+xgot".into();
     base.max_atomic_width = Some(64);
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index bc464b099e2..b9acadc406e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -51,6 +51,7 @@ use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
 use rustc_abi::ExternAbi;
+use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{
     Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
@@ -73,7 +74,7 @@ use rustc_middle::ty::{
     TypeVisitableExt,
 };
 use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym};
+use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym};
 use tracing::{debug, instrument};
 
 use crate::error_reporting::TypeErrCtxt;
@@ -225,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         struct AbsolutePathPrinter<'tcx> {
             tcx: TyCtxt<'tcx>,
-            segments: Vec<String>,
+            segments: Vec<Symbol>,
         }
 
         impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
@@ -253,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
 
             fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
-                self.segments = vec![self.tcx.crate_name(cnum).to_string()];
+                self.segments = vec![self.tcx.crate_name(cnum)];
                 Ok(())
             }
             fn path_qualified(
@@ -279,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 disambiguated_data: &DisambiguatedDefPathData,
             ) -> Result<(), PrintError> {
                 print_prefix(self)?;
-                self.segments.push(disambiguated_data.to_string());
+                self.segments.push(disambiguated_data.as_sym(true));
                 Ok(())
             }
             fn path_generic_args(
@@ -314,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // known" by the same name, we use the "absolute path" which uses the original
                 // crate name instead.
                 let (expected, found) = if expected_str == found_str {
-                    (expected_abs.join("::"), found_abs.join("::"))
+                    (join_path_syms(&expected_abs), join_path_syms(&found_abs))
                 } else {
                     (expected_str.clone(), found_str.clone())
                 };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 712e88300ff..98f67257fd1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -12,6 +12,7 @@ use rustc_infer::traits::{
     Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
+use rustc_session::parse::feature_err_unstable_feature_bound;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use tracing::{debug, instrument};
 
@@ -611,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 )
                 .with_span_label(span, format!("cannot normalize `{alias}`"))
             }
+            ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+
+                let mut err;
+
+                if self.tcx.features().staged_api() {
+                    err = self.dcx().struct_span_err(
+                        span,
+                        format!("unstable feature `{sym}` is used without being enabled."),
+                    );
+
+                    err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`"));
+                } else {
+                    err = feature_err_unstable_feature_bound(
+                        &self.tcx.sess,
+                        sym,
+                        span,
+                        format!("use of unstable library feature `{sym}`"),
+                    );
+                }
+                err
+            }
 
             _ => {
                 if let Some(e) = self.tainted_by_errors() {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index cd3e6c4bc54..1ac309da101 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     | ty::PredicateKind::ConstEquate { .. }
                     // Ambiguous predicates should never error
                     | ty::PredicateKind::Ambiguous
+                    // We never return Err when proving UnstableFeature goal.
+                    | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. })
                     | ty::PredicateKind::NormalizesTo { .. }
                     | ty::PredicateKind::AliasRelate { .. }
                     | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index d4cc1ceb280..1d8b934cef3 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -453,7 +453,7 @@ pub fn report_dyn_incompatibility<'tcx>(
     let trait_str = tcx.def_path_str(trait_def_id);
     let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
         hir::Node::Item(item) => match item.kind {
-            hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => {
+            hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => {
                 Some(ident.span)
             }
             _ => unreachable!(),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index bd1d29826e6..bf7d4257b62 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -22,6 +22,7 @@ use rustc_hir::{
     expr_needs_parens, is_range_literal,
 };
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
+use rustc_middle::middle::privacy::Level;
 use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::{
@@ -267,7 +268,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             let node = self.tcx.hir_node_by_def_id(body_id);
             match node {
                 hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _),
+                    kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _),
                     ..
                 }) if self_ty == self.tcx.types.self_param => {
                     assert!(param_ty);
@@ -330,7 +331,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
                 hir::Node::Item(hir::Item {
                     kind:
-                        hir::ItemKind::Trait(_, _, _, generics, ..)
+                        hir::ItemKind::Trait(_, _, _, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. }),
                     ..
                 }) if projection.is_some() => {
@@ -354,7 +355,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         hir::ItemKind::Struct(_, generics, _)
                         | hir::ItemKind::Enum(_, generics, _)
                         | hir::ItemKind::Union(_, generics, _)
-                        | hir::ItemKind::Trait(_, _, _, generics, ..)
+                        | hir::ItemKind::Trait(_, _, _, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. })
                         | hir::ItemKind::Fn { generics, .. }
                         | hir::ItemKind::TyAlias(_, generics, _)
@@ -414,7 +415,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         hir::ItemKind::Struct(_, generics, _)
                         | hir::ItemKind::Enum(_, generics, _)
                         | hir::ItemKind::Union(_, generics, _)
-                        | hir::ItemKind::Trait(_, _, _, generics, ..)
+                        | hir::ItemKind::Trait(_, _, _, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. })
                         | hir::ItemKind::Fn { generics, .. }
                         | hir::ItemKind::TyAlias(_, generics, _)
@@ -2870,11 +2871,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         ty::ClauseKind::Trait(trait_pred) => {
                             let def_id = trait_pred.def_id();
                             let visible_item = if let Some(local) = def_id.as_local() {
-                                // Check for local traits being reachable.
-                                let vis = &tcx.resolutions(()).effective_visibilities;
-                                // Account for non-`pub` traits in the root of the local crate.
-                                let is_locally_reachable = tcx.parent(def_id).is_crate_root();
-                                vis.is_reachable(local) || is_locally_reachable
+                                let ty = trait_pred.self_ty();
+                                // when `TraitA: TraitB` and `S` only impl TraitA,
+                                // we check if `TraitB` can be reachable from `S`
+                                // to determine whether to note `TraitA` is sealed trait.
+                                if let ty::Adt(adt, _) = ty.kind() {
+                                    let visibilities = tcx.effective_visibilities(());
+                                    visibilities.effective_vis(local).is_none_or(|v| {
+                                        v.at_level(Level::Reexported)
+                                            .is_accessible_from(adt.did(), tcx)
+                                    })
+                                } else {
+                                    // FIXME(xizheyin): if the type is not ADT, we should not suggest it
+                                    true
+                                }
                             } else {
                                 // Check for foreign traits being reachable.
                                 tcx.visible_parent_map(()).get(&def_id).is_some()
@@ -3436,7 +3446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let mut is_auto_trait = false;
                 match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
                     Some(Node::Item(hir::Item {
-                        kind: hir::ItemKind::Trait(is_auto, _, ident, ..),
+                        kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..),
                         ..
                     })) => {
                         // FIXME: we should do something else so that it works even on crate foreign
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 90cdf75265d..7901d52dffb 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -534,7 +534,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                     match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
                     {
                         hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Trait(_, _, _, generics, ..),
+                            kind: hir::ItemKind::Trait(_, _, _, _, generics, ..),
                             ..
                         })
                         | hir::Node::Item(hir::Item {
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 0118321befb..7c6b7b14ecb 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -33,8 +33,8 @@ impl<'tcx> InferCtxt<'tcx> {
         let ty = self.resolve_vars_if_possible(ty);
 
         // FIXME(#132279): This should be removed as it causes us to incorrectly
-        // handle opaques in their defining scope.
-        if !self.next_trait_solver() && !(param_env, ty).has_infer() {
+        // handle opaques in their defining scope, and stalled coroutines.
+        if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() {
             return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty);
         }
 
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 068e90b00b8..2b33b8ac9f8 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError};
 use rustc_macros::extension;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, elaborate};
 
 use crate::traits::ScrubbedTraitError;
 use crate::traits::outlives_bounds::InferCtxtExt;
@@ -46,6 +46,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
             }
         }
 
+        // FIXME(-Znext-trait-solver): Normalize these.
+        let higher_ranked_assumptions = infcx.take_registered_region_assumptions();
+        let higher_ranked_assumptions =
+            elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions);
+
         // FIXME: This needs to be modified so that we normalize the known type
         // outlives obligations then elaborate them into their region/type components.
         // Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
@@ -59,6 +64,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
                 assumed_wf_tys,
                 disable_implied_bounds_hack,
             ),
+            higher_ranked_assumptions,
         )
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs
index 5a5d16167d2..f58961683a9 100644
--- a/compiler/rustc_trait_selection/src/solve.rs
+++ b/compiler/rustc_trait_selection/src/solve.rs
@@ -7,7 +7,7 @@ mod normalize;
 mod select;
 
 pub(crate) use delegate::SolverDelegate;
-pub use fulfill::{FulfillmentCtxt, NextSolverError};
+pub use fulfill::{FulfillmentCtxt, NextSolverError, StalledOnCoroutines};
 pub(crate) use normalize::deeply_normalize_for_diagnostics;
 pub use normalize::{
     deeply_normalize, deeply_normalize_with_skipped_universes,
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 1a24254d57f..7426504e139 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -12,11 +12,11 @@ use rustc_infer::traits::solve::Goal;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::{
-    self, SizedTraitKind, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
+    self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
 };
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 
-use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph};
+use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph};
 
 #[repr(transparent)]
 pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@@ -76,19 +76,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
             if trait_pred.polarity() == ty::PredicatePolarity::Positive {
                 match self.0.tcx.as_lang_item(trait_pred.def_id()) {
-                    Some(LangItem::Sized)
-                        if self
-                            .resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
-                            .has_trivial_sizedness(self.0.tcx, SizedTraitKind::Sized) =>
-                    {
-                        return Some(Certainty::Yes);
-                    }
-                    Some(LangItem::MetaSized)
-                        if self
-                            .resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
-                            .has_trivial_sizedness(self.0.tcx, SizedTraitKind::MetaSized) =>
-                    {
-                        return Some(Certainty::Yes);
+                    Some(LangItem::Sized) | Some(LangItem::MetaSized) => {
+                        let predicate = self.resolve_vars_if_possible(goal.predicate);
+                        if sizedness_fast_path(self.tcx, predicate, goal.param_env) {
+                            return Some(Certainty::Yes);
+                        }
                     }
                     Some(LangItem::Copy | LangItem::Clone) => {
                         let self_ty =
@@ -206,14 +198,18 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
     }
 
-    fn make_deduplicated_outlives_constraints(
-        &self,
-    ) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
+    fn make_deduplicated_outlives_constraints(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> {
         // Cannot use `take_registered_region_obligations` as we may compute the response
         // inside of a `probe` whenever we have multiple choices inside of the solver.
         let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
+        let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned();
         let region_constraints = self.0.with_region_constraints(|region_constraints| {
-            make_query_region_constraints(self.tcx, region_obligations, region_constraints)
+            make_query_region_constraints(
+                self.tcx,
+                region_obligations,
+                region_constraints,
+                region_assumptions,
+            )
         });
 
         let mut seen = FxHashSet::default();
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index d56042a5ca2..3ce0f025512 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -10,7 +10,8 @@ use rustc_infer::traits::{
     FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
 };
 use rustc_middle::ty::{
-    self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode,
+    self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+    TypingMode,
 };
 use rustc_next_trait_solver::delegate::SolverDelegate as _;
 use rustc_next_trait_solver::solve::{
@@ -254,7 +255,7 @@ where
         &mut self,
         infcx: &InferCtxt<'tcx>,
     ) -> PredicateObligations<'tcx> {
-        let stalled_generators = match infcx.typing_mode() {
+        let stalled_coroutines = match infcx.typing_mode() {
             TypingMode::Analysis { defining_opaque_types_and_generators } => {
                 defining_opaque_types_and_generators
             }
@@ -264,7 +265,7 @@ where
             | TypingMode::PostAnalysis => return Default::default(),
         };
 
-        if stalled_generators.is_empty() {
+        if stalled_coroutines.is_empty() {
             return Default::default();
         }
 
@@ -275,7 +276,7 @@ where
                         .visit_proof_tree(
                             obl.as_goal(),
                             &mut StalledOnCoroutines {
-                                stalled_generators,
+                                stalled_coroutines,
                                 span: obl.cause.span,
                                 cache: Default::default(),
                             },
@@ -297,10 +298,10 @@ where
 ///
 /// This function can be also return false positives, which will lead to poor diagnostics
 /// so we want to keep this visitor *precise* too.
-struct StalledOnCoroutines<'tcx> {
-    stalled_generators: &'tcx ty::List<LocalDefId>,
-    span: Span,
-    cache: DelayedSet<Ty<'tcx>>,
+pub struct StalledOnCoroutines<'tcx> {
+    pub stalled_coroutines: &'tcx ty::List<LocalDefId>,
+    pub span: Span,
+    pub cache: DelayedSet<Ty<'tcx>>,
 }
 
 impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> {
@@ -330,12 +331,14 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for StalledOnCoroutines<'tcx> {
         }
 
         if let ty::CoroutineWitness(def_id, _) = *ty.kind()
-            && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id))
+            && def_id.as_local().is_some_and(|def_id| self.stalled_coroutines.contains(&def_id))
         {
-            return ControlFlow::Break(());
+            ControlFlow::Break(())
+        } else if ty.has_coroutines() {
+            ty.super_visit_with(self)
+        } else {
+            ControlFlow::Continue(())
         }
-
-        ty.super_visit_with(self)
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 3ae908ec16b..759db1d18c0 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
                 | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
                 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
                 ty::PredicateKind::Ambiguous => return false,
             };
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index ce5a4edeaaa..f50f01a285b 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -461,6 +461,7 @@ fn impl_intersection_has_negative_obligation(
     // requirements, when proving the negated where clauses below.
     drop(equate_obligations);
     drop(infcx.take_registered_region_obligations());
+    drop(infcx.take_registered_region_assumptions());
     drop(infcx.take_and_reset_region_constraints());
 
     plug_infer_with_placeholders(
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 9a4f3887bbb..ea1eed95723 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>(
         // FIXME(generic_const_exprs): this can mention `Self`
         | ty::ClauseKind::ConstEvaluatable(..)
         | ty::ClauseKind::HostEffect(..)
+        | ty::ClauseKind::UnstableFeature(_)
          => None,
     }
 }
@@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         | ty::ClauseKind::ConstArgHasType(_, _)
         | ty::ClauseKind::WellFormed(_)
         | ty::ClauseKind::ConstEvaluatable(_)
+        | ty::ClauseKind::UnstableFeature(_)
         | ty::ClauseKind::HostEffect(..) => false,
     })
 }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 64a51e0550b..6b884b36080 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -3,6 +3,7 @@ use std::marker::PhantomData;
 use rustc_data_structures::obligation_forest::{
     Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult,
 };
+use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::{
     FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError,
@@ -11,7 +12,11 @@ use rustc_infer::traits::{
 use rustc_middle::bug;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{
+    self, Binder, Const, GenericArgsRef, TypeVisitable, TypeVisitableExt, TypingMode,
+    may_use_unstable_feature,
+};
+use rustc_span::DUMMY_SP;
 use thin_vec::{ThinVec, thin_vec};
 use tracing::{debug, debug_span, instrument};
 
@@ -24,6 +29,7 @@ use super::{
 };
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::{InferCtxt, TyOrConstInferVar};
+use crate::solve::StalledOnCoroutines;
 use crate::traits::normalize::normalize_with_depth_to;
 use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -166,8 +172,25 @@ where
         &mut self,
         infcx: &InferCtxt<'tcx>,
     ) -> PredicateObligations<'tcx> {
-        let mut processor =
-            DrainProcessor { removed_predicates: PredicateObligations::new(), infcx };
+        let stalled_coroutines = match infcx.typing_mode() {
+            TypingMode::Analysis { defining_opaque_types_and_generators } => {
+                defining_opaque_types_and_generators
+            }
+            TypingMode::Coherence
+            | TypingMode::Borrowck { defining_opaque_types: _ }
+            | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ }
+            | TypingMode::PostAnalysis => return Default::default(),
+        };
+
+        if stalled_coroutines.is_empty() {
+            return Default::default();
+        }
+
+        let mut processor = DrainProcessor {
+            infcx,
+            removed_predicates: PredicateObligations::new(),
+            stalled_coroutines,
+        };
         let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor);
         assert!(outcome.errors.is_empty());
         return processor.removed_predicates;
@@ -175,6 +198,7 @@ where
         struct DrainProcessor<'a, 'tcx> {
             infcx: &'a InferCtxt<'tcx>,
             removed_predicates: PredicateObligations<'tcx>,
+            stalled_coroutines: &'tcx ty::List<LocalDefId>,
         }
 
         impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> {
@@ -183,10 +207,14 @@ where
             type OUT = Outcome<Self::Obligation, Self::Error>;
 
             fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
-                pending_obligation
-                    .stalled_on
-                    .iter()
-                    .any(|&var| self.infcx.ty_or_const_infer_var_changed(var))
+                self.infcx
+                    .resolve_vars_if_possible(pending_obligation.obligation.predicate)
+                    .visit_with(&mut StalledOnCoroutines {
+                        stalled_coroutines: self.stalled_coroutines,
+                        span: DUMMY_SP,
+                        cache: Default::default(),
+                    })
+                    .is_break()
             }
 
             fn process_obligation(
@@ -335,7 +363,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
 
         let infcx = self.selcx.infcx;
 
-        if sizedness_fast_path(infcx.tcx, obligation.predicate) {
+        if sizedness_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) {
             return ProcessResult::Changed(thin_vec![]);
         }
 
@@ -404,6 +432,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::AliasRelate(..) => {
                     bug!("AliasRelate is only used by the new solver")
                 }
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => {
+                   unreachable!("unexpected higher ranked `UnstableFeature` goal")
+                }
             },
             Some(pred) => match pred {
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
@@ -767,6 +798,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         }
                     }
                 }
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
+                    if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) {
+                        ProcessResult::Changed(Default::default())
+                    } else {
+                        ProcessResult::Unchanged
+                    }
+                }
             },
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 59d3ac21387..53518038f8d 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -78,7 +78,10 @@ fn implied_outlives_bounds<'a, 'tcx>(
     bounds.retain(|bound| !bound.has_placeholders());
 
     if !constraints.is_empty() {
-        let QueryRegionConstraints { outlives } = constraints;
+        // FIXME(higher_ranked_auto): Should we register assumptions here?
+        // We otherwise would get spurious errors if normalizing an implied
+        // outlives bound required proving some higher-ranked coroutine obl.
+        let QueryRegionConstraints { outlives, assumptions: _ } = constraints;
         let cause = ObligationCause::misc(span, body_id);
         for &(predicate, _) in &outlives {
             infcx.register_outlives_constraint(predicate, &cause);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 3b549244431..f027ba1c5cb 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -80,6 +80,11 @@ where
         pre_obligations.is_empty(),
         "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}",
     );
+    let pre_assumptions = infcx.take_registered_region_assumptions();
+    assert!(
+        pre_assumptions.is_empty(),
+        "scrape_region_constraints: incoming region assumptions = {pre_assumptions:#?}",
+    );
 
     let value = infcx.commit_if_ok(|_| {
         let ocx = ObligationCtxt::new(infcx);
@@ -100,11 +105,13 @@ where
     let value = infcx.resolve_vars_if_possible(value);
 
     let region_obligations = infcx.take_registered_region_obligations();
+    let region_assumptions = infcx.take_registered_region_assumptions();
     let region_constraint_data = infcx.take_and_reset_region_constraints();
     let region_constraints = query_response::make_query_region_constraints(
         infcx.tcx,
         region_obligations,
         &region_constraint_data,
+        region_assumptions,
     );
 
     if region_constraints.is_empty() {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index e294f7839aa..7540cbe3fd1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::NormalizesTo(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
                 | ty::PredicateKind::AliasRelate(..) => {}
 
                 // We need to search through *all* WellFormed predicates
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 4bdf04311a0..018e9748cf0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -180,8 +180,9 @@ where
             span,
         )?;
         output.error_info = error_info;
-        if let Some(QueryRegionConstraints { outlives }) = output.constraints {
+        if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints {
             region_constraints.outlives.extend(outlives.iter().cloned());
+            region_constraints.assumptions.extend(assumptions.iter().cloned());
         }
         output.constraints = if region_constraints.is_empty() {
             None
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 22eeb285b37..f24214145ba 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -15,7 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
         tcx: TyCtxt<'tcx>,
         key: &ParamEnvAnd<'tcx, Self>,
     ) -> Option<Self::QueryResponse> {
-        if sizedness_fast_path(tcx, key.value.predicate) {
+        if sizedness_fast_path(tcx, key.value.predicate, key.param_env) {
             return Some(());
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index cc188a280aa..2c7089507a8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -842,6 +842,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
+                ty::CoroutineWitness(def_id, _) => {
+                    if self.should_stall_coroutine_witness(def_id) {
+                        candidates.ambiguous = true;
+                    } else {
+                        candidates.vec.push(AutoImplCandidate);
+                    }
+                }
+
                 ty::Bool
                 | ty::Char
                 | ty::Int(_)
@@ -861,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Coroutine(..)
                 | ty::Never
                 | ty::Tuple(_)
-                | ty::CoroutineWitness(..)
                 | ty::UnsafeBinder(_) => {
                     // Only consider auto impls of unsafe traits when there are
                     // no unsafe fields.
@@ -1119,12 +1126,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match *self_ty.kind() {
             // These impls are built-in because we cannot express sufficiently
             // generic impls in libcore.
-            ty::FnDef(..)
-            | ty::FnPtr(..)
-            | ty::Error(_)
-            | ty::Tuple(..)
-            | ty::CoroutineWitness(..)
-            | ty::Pat(..) => {
+            ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::Tuple(..) | ty::Pat(..) => {
                 candidates.vec.push(BuiltinCandidate);
             }
 
@@ -1192,6 +1194,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
+            ty::CoroutineWitness(coroutine_def_id, _) => {
+                if self.should_stall_coroutine_witness(coroutine_def_id) {
+                    candidates.ambiguous = true;
+                } else {
+                    candidates.vec.push(SizedCandidate);
+                }
+            }
+
             // Fallback to whatever user-defined impls or param-env clauses exist in this case.
             ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {}
 
@@ -1229,7 +1239,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Char
             | ty::Ref(..)
             | ty::Coroutine(..)
-            | ty::CoroutineWitness(..)
             | ty::Array(..)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
@@ -1238,6 +1247,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 candidates.vec.push(SizedCandidate);
             }
 
+            ty::CoroutineWitness(coroutine_def_id, _) => {
+                if self.should_stall_coroutine_witness(coroutine_def_id) {
+                    candidates.ambiguous = true;
+                } else {
+                    candidates.vec.push(SizedCandidate);
+                }
+            }
+
             // Conditionally `Sized`.
             ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => {
                 candidates.vec.push(SizedCandidate);
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index ee8cef20279..488094b15ac 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -411,18 +411,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
             let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty);
 
-            let types = self.constituent_types_for_ty(self_ty)?;
-            let types = self.infcx.enter_forall_and_leak_universe(types);
+            let constituents = self.constituent_types_for_auto_trait(self_ty)?;
+            let constituents = self.infcx.enter_forall_and_leak_universe(constituents);
 
             let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
-            let obligations = self.collect_predicates_for_types(
+            let mut obligations = self.collect_predicates_for_types(
                 obligation.param_env,
-                cause,
+                cause.clone(),
                 obligation.recursion_depth + 1,
                 obligation.predicate.def_id(),
-                types,
+                constituents.types,
             );
 
+            // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types`
+            // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really
+            // matter yet.
+            for assumption in constituents.assumptions {
+                let assumption = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    cause.clone(),
+                    obligation.recursion_depth + 1,
+                    assumption,
+                    &mut obligations,
+                );
+                self.infcx.register_region_assumption(assumption);
+            }
+
             Ok(obligations)
         })
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2e65750db25..f90316f520b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -20,6 +20,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::traits::{PredicateObligations, TraitObligation};
+use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
 pub use rustc_middle::traits::select::*;
@@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
     self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
-    TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
+    TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature,
 };
 use rustc_span::{Symbol, sym};
 use tracing::{debug, instrument, trace};
@@ -596,7 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None => self.check_recursion_limit(&obligation, &obligation)?,
         }
 
-        if sizedness_fast_path(self.tcx(), obligation.predicate) {
+        if sizedness_fast_path(self.tcx(), obligation.predicate, obligation.param_env) {
             return Ok(EvaluatedToOk);
         }
 
@@ -832,6 +833,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
+                ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
+                    if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) {
+                        Ok(EvaluatedToOk)
+                    } else {
+                        Ok(EvaluatedToAmbig)
+                    }
+                }
+
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
                     match const_evaluatable::is_const_evaluatable(
                         self.infcx,
@@ -1504,7 +1513,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 defining_opaque_types_and_generators: defining_opaque_types,
             }
             | TypingMode::Borrowck { defining_opaque_types } => {
-                defining_opaque_types.is_empty() || !pred.has_opaque_types()
+                defining_opaque_types.is_empty()
+                    || (!pred.has_opaque_types() && !pred.has_coroutines())
             }
             // The hidden types of `defined_opaque_types` is not local to the current
             // inference context, so we can freely move this to the global cache.
@@ -2247,10 +2257,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
     /// ```
     #[instrument(level = "debug", skip(self), ret)]
-    fn constituent_types_for_ty(
+    fn constituent_types_for_auto_trait(
         &self,
         t: Ty<'tcx>,
-    ) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> {
+    ) -> Result<ty::Binder<'tcx, AutoImplConstituents<'tcx>>, SelectionError<'tcx>> {
         Ok(match *t.kind() {
             ty::Uint(_)
             | ty::Int(_)
@@ -2261,17 +2271,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Error(_)
             | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Never
-            | ty::Char => ty::Binder::dummy(Vec::new()),
+            | ty::Char => {
+                ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] })
+            }
 
             // This branch is only for `experimental_default_bounds`.
             // Other foreign types were rejected earlier in
             // `assemble_candidates_from_auto_impls`.
-            ty::Foreign(..) => ty::Binder::dummy(Vec::new()),
+            ty::Foreign(..) => {
+                ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] })
+            }
 
-            ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]),
+            ty::UnsafeBinder(ty) => {
+                ty.map_bound(|ty| AutoImplConstituents { types: vec![ty], assumptions: vec![] })
+            }
 
             // Treat this like `struct str([u8]);`
-            ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]),
+            ty::Str => ty::Binder::dummy(AutoImplConstituents {
+                types: vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)],
+                assumptions: vec![],
+            }),
 
             ty::Placeholder(..)
             | ty::Dynamic(..)
@@ -2283,30 +2302,41 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             }
 
             ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
-                ty::Binder::dummy(vec![element_ty])
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: vec![element_ty],
+                    assumptions: vec![],
+                })
             }
 
-            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]),
+            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => {
+                ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
+            }
 
             ty::Tuple(tys) => {
                 // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-                ty::Binder::dummy(tys.iter().collect())
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: tys.iter().collect(),
+                    assumptions: vec![],
+                })
             }
 
             ty::Closure(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
-                ty::Binder::dummy(vec![ty])
+                ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
             }
 
             ty::CoroutineClosure(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
-                ty::Binder::dummy(vec![ty])
+                ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
             }
 
             ty::Coroutine(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                 let witness = args.as_coroutine().witness();
-                ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect())
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: [ty].into_iter().chain(iter::once(witness)).collect(),
+                    assumptions: vec![],
+                })
             }
 
             ty::CoroutineWitness(def_id, args) => self
@@ -2314,16 +2344,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 .tcx
                 .coroutine_hidden_types(def_id)
                 .instantiate(self.infcx.tcx, args)
-                .map_bound(|witness| witness.types.to_vec()),
+                .map_bound(|witness| AutoImplConstituents {
+                    types: witness.types.to_vec(),
+                    assumptions: witness.assumptions.to_vec(),
+                }),
 
             // For `PhantomData<T>`, we pass `T`.
             ty::Adt(def, args) if def.is_phantom_data() => {
-                ty::Binder::dummy(args.types().collect())
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: args.types().collect(),
+                    assumptions: vec![],
+                })
             }
 
-            ty::Adt(def, args) => {
-                ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect())
-            }
+            ty::Adt(def, args) => ty::Binder::dummy(AutoImplConstituents {
+                types: def.all_fields().map(|f| f.ty(self.tcx(), args)).collect(),
+                assumptions: vec![],
+            }),
 
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
                 if self.infcx.can_define_opaque_ty(def_id) {
@@ -2333,7 +2370,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     // which enforces a DAG between the functions requiring
                     // the auto trait bounds in question.
                     match self.tcx().type_of_opaque(def_id) {
-                        Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]),
+                        Ok(ty) => ty::Binder::dummy(AutoImplConstituents {
+                            types: vec![ty.instantiate(self.tcx(), args)],
+                            assumptions: vec![],
+                        }),
                         Err(_) => {
                             return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
                         }
@@ -2803,6 +2843,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
         obligations
     }
+
+    fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool {
+        match self.infcx.typing_mode() {
+            TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => {
+                def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
+            }
+            TypingMode::Coherence
+            | TypingMode::PostAnalysis
+            | TypingMode::Borrowck { defining_opaque_types: _ }
+            | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => false,
+        }
+    }
 }
 
 impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
@@ -3113,3 +3165,9 @@ pub(crate) enum ProjectionMatchesProjection {
     Ambiguous,
     No,
 }
+
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
+pub(crate) struct AutoImplConstituents<'tcx> {
+    pub types: Vec<Ty<'tcx>>,
+    pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 141454bfe37..c3d60ec45c4 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>(
             | ty::ClauseKind::ConstArgHasType(_, _)
             | ty::ClauseKind::WellFormed(_)
             | ty::ClauseKind::ConstEvaluatable(_)
+            | ty::ClauseKind::UnstableFeature(_)
             | ty::ClauseKind::HostEffect(..) => {}
         }
     }
@@ -364,7 +365,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
     }
 }
 
-pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool {
+pub fn sizedness_fast_path<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    predicate: ty::Predicate<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> bool {
     // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
     // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
     // canonicalize and all that for such cases.
@@ -378,10 +383,31 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
             _ => return false,
         };
 
+        // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature
+        // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs`
+        // is pending a proper fix
+        if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) {
+            return true;
+        }
+
         if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
             debug!("fast path -- trivial sizedness");
             return true;
         }
+
+        if matches!(trait_pred.self_ty().kind(), ty::Param(_) | ty::Placeholder(_)) {
+            for clause in param_env.caller_bounds() {
+                if let ty::ClauseKind::Trait(clause_pred) = clause.kind().skip_binder()
+                    && clause_pred.polarity == ty::PredicatePolarity::Positive
+                    && clause_pred.self_ty() == trait_pred.self_ty()
+                    && (clause_pred.def_id() == trait_pred.def_id()
+                        || (sizedness == SizedTraitKind::MetaSized
+                            && tcx.is_lang_item(clause_pred.def_id(), LangItem::Sized)))
+                {
+                    return true;
+                }
+            }
+        }
     }
 
     false
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index fed9f254cdf..adce9850b59 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>(
         ty::ClauseKind::ConstEvaluatable(ct) => {
             wf.add_wf_preds_for_term(ct.into());
         }
+        ty::ClauseKind::UnstableFeature(_) => {}
     }
 
     wf.normalize(infcx)
@@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>(
                 | ty::ClauseKind::Projection(_)
                 | ty::ClauseKind::ConstArgHasType(_, _)
                 | ty::ClauseKind::WellFormed(_)
+                | ty::ClauseKind::UnstableFeature(_)
                 | ty::ClauseKind::ConstEvaluatable(_) => None,
             }
         })
diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs
index 447e13126cc..87d17f3e131 100644
--- a/compiler/rustc_traits/src/coroutine_witnesses.rs
+++ b/compiler/rustc_traits/src/coroutine_witnesses.rs
@@ -1,5 +1,10 @@
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, TyCtxt, fold_regions};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::traits::{Obligation, ObligationCause};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions};
+use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars};
 
 /// Return the set of types that should be taken into account when checking
 /// trait bounds on a coroutine's internal state. This properly replaces
@@ -30,8 +35,57 @@ pub(crate) fn coroutine_hidden_types<'tcx>(
             }),
     );
 
+    let assumptions = compute_assumptions(tcx, def_id, bound_tys);
+
     ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
-        ty::CoroutineWitnessTypes { types: bound_tys },
+        ty::CoroutineWitnessTypes { types: bound_tys, assumptions },
         tcx.mk_bound_variable_kinds(&vars),
     ))
 }
+
+fn compute_assumptions<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    bound_tys: &'tcx ty::List<Ty<'tcx>>,
+) -> &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>> {
+    let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis {
+        defining_opaque_types_and_generators: ty::List::empty(),
+    });
+    with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| {
+        let param_env = tcx.param_env(def_id);
+        let ocx = ObligationCtxt::new(&infcx);
+
+        ocx.register_obligations(bound_tys.iter().map(|ty| {
+            Obligation::new(
+                tcx,
+                ObligationCause::dummy(),
+                param_env,
+                ty::ClauseKind::WellFormed(ty.into()),
+            )
+        }));
+        let _errors = ocx.select_all_or_error();
+
+        let region_obligations = infcx.take_registered_region_obligations();
+        let region_assumptions = infcx.take_registered_region_assumptions();
+        let region_constraints = infcx.take_and_reset_region_constraints();
+
+        let outlives = make_query_region_constraints(
+            tcx,
+            region_obligations,
+            &region_constraints,
+            region_assumptions,
+        )
+        .outlives
+        .fold_with(&mut OpportunisticRegionResolver::new(&infcx));
+
+        tcx.mk_outlives_from_iter(
+            outlives
+                .into_iter()
+                .map(|(o, _)| o)
+                // FIXME(higher_ranked_auto): We probably should deeply resolve these before
+                // filtering out infers which only correspond to unconstrained infer regions
+                // which we can sometimes get.
+                .filter(|o| !o.has_infer()),
+        )
+    })
+}
diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs
index 7771db855d7..819b8e3231c 100644
--- a/compiler/rustc_traits/src/evaluate_obligation.rs
+++ b/compiler/rustc_traits/src/evaluate_obligation.rs
@@ -24,7 +24,7 @@ fn evaluate_obligation<'tcx>(
     debug!("evaluate_obligation: goal={:#?}", goal);
     let ParamEnvAnd { param_env, value: predicate } = goal;
 
-    if sizedness_fast_path(tcx, predicate) {
+    if sizedness_fast_path(tcx, predicate, param_env) {
         return Ok(EvaluationResult::EvaluatedToOk);
     }
 
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 68ff66bbce7..c1b848a2e79 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -57,6 +57,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
         | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
         | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
         | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
+        | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
         | ty::PredicateKind::NormalizesTo(..)
         | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 3b313edea6f..4a7263d0ccd 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -223,7 +223,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
             }
             // Skips type aliases, as they are meant to be transparent.
             // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly?
-            ty::Alias(ty::Free, alias_ty) if alias_ty.def_id.is_local() => {
+            ty::Alias(ty::Free, alias_ty) if let Some(def_id) = alias_ty.def_id.as_local() => {
+                if !self.seen.insert(def_id) {
+                    return;
+                }
                 self.tcx
                     .type_of(alias_ty.def_id)
                     .instantiate(self.tcx, alias_ty.args)
@@ -256,16 +259,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                                 return;
                             }
 
-                            let impl_args = alias_ty.args.rebase_onto(
+                            let alias_args = alias_ty.args.rebase_onto(
                                 self.tcx,
                                 impl_trait_ref.def_id,
                                 ty::GenericArgs::identity_for_item(self.tcx, parent),
                             );
 
-                            if self.tcx.check_args_compatible(assoc.def_id, impl_args) {
+                            if self.tcx.check_args_compatible(assoc.def_id, alias_args) {
                                 self.tcx
                                     .type_of(assoc.def_id)
-                                    .instantiate(self.tcx, impl_args)
+                                    .instantiate(self.tcx, alias_args)
                                     .visit_with(self);
                                 return;
                             } else {
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 7ffcf7b5d96..dc15cc3eb55 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -234,6 +234,9 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
             ty::ClauseKind::ConstArgHasType(..) => {
                 // Nothing to elaborate
             }
+            ty::ClauseKind::UnstableFeature(_) => {
+                // Nothing to elaborate
+            }
         }
     }
 }
@@ -368,3 +371,54 @@ impl<I: Interner, It: Iterator<Item = I::Clause>> Iterator for FilterToTraits<I,
         (0, upper)
     }
 }
+
+pub fn elaborate_outlives_assumptions<I: Interner>(
+    cx: I,
+    assumptions: impl IntoIterator<Item = ty::OutlivesPredicate<I, I::GenericArg>>,
+) -> HashSet<ty::OutlivesPredicate<I, I::GenericArg>> {
+    let mut collected = HashSet::default();
+
+    for ty::OutlivesPredicate(arg1, r2) in assumptions {
+        collected.insert(ty::OutlivesPredicate(arg1, r2));
+        match arg1.kind() {
+            // Elaborate the components of an type, since we may have substituted a
+            // generic coroutine with a more specific type.
+            ty::GenericArgKind::Type(ty1) => {
+                let mut components = smallvec![];
+                push_outlives_components(cx, ty1, &mut components);
+                for c in components {
+                    match c {
+                        Component::Region(r1) => {
+                            if !r1.is_bound() {
+                                collected.insert(ty::OutlivesPredicate(r1.into(), r2));
+                            }
+                        }
+
+                        Component::Param(p) => {
+                            let ty = Ty::new_param(cx, p);
+                            collected.insert(ty::OutlivesPredicate(ty.into(), r2));
+                        }
+
+                        Component::Placeholder(p) => {
+                            let ty = Ty::new_placeholder(cx, p);
+                            collected.insert(ty::OutlivesPredicate(ty.into(), r2));
+                        }
+
+                        Component::Alias(alias_ty) => {
+                            collected.insert(ty::OutlivesPredicate(alias_ty.to_ty(cx).into(), r2));
+                        }
+
+                        Component::UnresolvedInferenceVariable(_) | Component::EscapingAlias(_) => {
+                        }
+                    }
+                }
+            }
+            // Nothing to elaborate for a region.
+            ty::GenericArgKind::Lifetime(_) => {}
+            // Consts don't really participate in outlives.
+            ty::GenericArgKind::Const(_) => {}
+        }
+    }
+
+    collected
+}
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 37cc2baa402..d7b9e0ca340 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -130,6 +130,12 @@ bitflags::bitflags! {
 
         /// Does this have any binders with bound vars (e.g. that need to be anonymized)?
         const HAS_BINDER_VARS             = 1 << 23;
+
+        /// Does this type have any coroutine witnesses in it?
+        // FIXME: This should probably be changed to track whether the type has any
+        // *coroutines* in it, though this will happen if we remove coroutine witnesses
+        // altogether.
+        const HAS_TY_CORO                 = 1 << 24;
     }
 }
 
@@ -240,10 +246,12 @@ impl<I: Interner> FlagComputation<I> {
                 self.add_flags(TypeFlags::HAS_TY_PARAM);
             }
 
-            ty::Closure(_, args)
-            | ty::Coroutine(_, args)
-            | ty::CoroutineClosure(_, args)
-            | ty::CoroutineWitness(_, args) => {
+            ty::Closure(_, args) | ty::Coroutine(_, args) | ty::CoroutineClosure(_, args) => {
+                self.add_args(args.as_slice());
+            }
+
+            ty::CoroutineWitness(_, args) => {
+                self.add_flags(TypeFlags::HAS_TY_CORO);
                 self.add_args(args.as_slice());
             }
 
@@ -401,7 +409,6 @@ impl<I: Interner> FlagComputation<I> {
                 self.add_const(expected);
                 self.add_const(found);
             }
-            ty::PredicateKind::Ambiguous => {}
             ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
                 self.add_alias_term(alias);
                 self.add_term(term);
@@ -410,6 +417,8 @@ impl<I: Interner> FlagComputation<I> {
                 self.add_term(t1);
                 self.add_term(t2);
             }
+            ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) => {}
+            ty::PredicateKind::Ambiguous => {}
         }
     }
 
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 6c77a90250a..e86a2305e23 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -285,3 +285,40 @@ pub trait InferCtxtLike: Sized {
 
     fn reset_opaque_types(&self);
 }
+
+pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
+    infcx: &'a Infcx,
+    param_env: I::ParamEnv,
+    symbol: I::Symbol,
+) -> bool
+where
+    Infcx: InferCtxtLike<Interner = I>,
+{
+    // Iterate through all goals in param_env to find the one that has the same symbol.
+    for pred in param_env.caller_bounds().iter() {
+        if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() {
+            if sym == symbol {
+                return true;
+            }
+        }
+    }
+
+    // During codegen we must assume that all feature bounds hold as we may be
+    // monomorphizing a body from an upstream crate which had an unstable feature
+    // enabled that we do not.
+    //
+    // Coherence should already report overlap errors involving unstable impls
+    // as the affected code would otherwise break when stabilizing this feature.
+    // It is also easily possible to accidentally cause unsoundness this way as
+    // we have to always enable unstable impls during codegen.
+    //
+    // Return ambiguity can also prevent people from writing code which depends on inference guidance
+    // that might no longer work after the impl is stabilised,
+    // tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs is one of the example.
+    //
+    // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
+    // if we are in std/core even if there is a corresponding `feature` attribute on the crate.
+
+    (infcx.typing_mode() == TypingMode::PostAnalysis)
+        || infcx.cx().features().feature_bound_holds_in_crate(symbol)
+}
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 2754d40fd36..0e307e15d5b 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -630,6 +630,8 @@ pub trait Features<I: Interner>: Copy {
     fn coroutine_clone(self) -> bool;
 
     fn associated_const_equality(self) -> bool;
+
+    fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool;
 }
 
 pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index dd3cf1fc181..e3231244577 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -106,6 +106,7 @@ pub trait Interner:
     type ParamTy: ParamLike;
     type BoundTy: BoundVarLike<Self>;
     type PlaceholderTy: PlaceholderLike<Self, Bound = Self::BoundTy>;
+    type Symbol: Copy + Hash + PartialEq + Eq + Debug;
 
     // Things stored inside of tys
     type ErrorGuaranteed: Copy + Debug + Hash + Eq;
@@ -145,6 +146,13 @@ pub trait Interner:
     type BoundRegion: BoundVarLike<Self>;
     type PlaceholderRegion: PlaceholderLike<Self, Bound = Self::BoundRegion>;
 
+    type RegionAssumptions: Copy
+        + Debug
+        + Hash
+        + Eq
+        + SliceLike<Item = ty::OutlivesPredicate<Self, Self::GenericArg>>
+        + TypeFoldable<Self>;
+
     // Predicates
     type ParamEnv: ParamEnv<Self>;
     type Predicate: Predicate<Self>;
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 4e41fd16ffd..8bc15ec4ff5 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -46,6 +46,13 @@ pub enum ClauseKind<I: Interner> {
     /// corresponding trait clause; this just enforces the *constness* of that
     /// implementation.
     HostEffect(ty::HostEffectPredicate<I>),
+
+    /// Support marking impl as unstable.
+    UnstableFeature(
+        #[type_foldable(identity)]
+        #[type_visitable(ignore)]
+        I::Symbol,
+    ),
 }
 
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
@@ -134,6 +141,9 @@ impl<I: Interner> fmt::Debug for ClauseKind<I> {
             ClauseKind::ConstEvaluatable(ct) => {
                 write!(f, "ConstEvaluatable({ct:?})")
             }
+            ClauseKind::UnstableFeature(feature_name) => {
+                write!(f, "UnstableFeature({feature_name:?})")
+            }
         }
     }
 }
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index db6fbefcf05..7c665424750 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -1150,4 +1150,5 @@ pub struct FnHeader<I: Interner> {
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 pub struct CoroutineWitnessTypes<I: Interner> {
     pub types: I::Tys,
+    pub assumptions: I::RegionAssumptions,
 }
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index a96ac97f785..5104484e9c4 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -269,6 +269,10 @@ pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
         self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
     }
 
+    fn has_coroutines(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_CORO)
+    }
+
     fn references_error(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_ERROR)
     }
diff --git a/library/Cargo.lock b/library/Cargo.lock
index c681c5935df..8b5275e5065 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -271,9 +271,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-literal-escaper"
-version = "0.0.4"
+version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
+checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
 dependencies = [
  "rustc-std-workspace-core",
  "rustc-std-workspace-std",
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 21425b9846e..1cce36606d2 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -5,7 +5,7 @@
 use core::error::Error;
 use core::fmt::{self, Debug, Display, Formatter};
 #[cfg(not(no_global_oom_handling))]
-use core::intrinsics::const_allocate;
+use core::intrinsics::{const_allocate, const_make_global};
 use core::marker::PhantomData;
 #[cfg(not(no_global_oom_handling))]
 use core::marker::Unsize;
@@ -340,9 +340,10 @@ impl<H> WithHeader<H> {
                     alloc.add(metadata_offset).cast();
                 // SAFETY: `*metadata_ptr` is within the allocation.
                 metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn));
-
+                // SAFETY: valid heap allocation
+                const_make_global(alloc);
                 // SAFETY: we have just written the metadata.
-                &*(metadata_ptr)
+                &*metadata_ptr
             }
         };
 
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index 30f42050ac8..d0ba9c39886 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -348,13 +348,13 @@
 //! format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}'
 //! argument := integer | identifier
 //!
-//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision]type
+//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
 //! fill := character
 //! align := '<' | '^' | '>'
 //! sign := '+' | '-'
 //! width := count
 //! precision := count | '*'
-//! type := '' | '?' | 'x?' | 'X?' | identifier
+//! type := '?' | 'x?' | 'X?' | identifier
 //! count := parameter | integer
 //! parameter := argument '$'
 //! ```
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 39cdf6efda0..38393379a78 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -783,7 +783,7 @@ impl TypeId {
 
         // This is a provenance-stripping memcpy.
         for (i, chunk) in self.data.iter().copied().enumerate() {
-            let chunk = chunk.expose_provenance().to_ne_bytes();
+            let chunk = chunk.addr().to_ne_bytes();
             let start = i * chunk.len();
             bytes[start..(start + chunk.len())].copy_from_slice(&chunk);
         }
diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs
index 069c50c2531..c21c08320be 100644
--- a/library/core/src/async_iter/async_iter.rs
+++ b/library/core/src/async_iter/async_iter.rs
@@ -28,15 +28,15 @@ pub trait AsyncIterator {
     /// async iterator state:
     ///
     /// - `Poll::Pending` means that this async iterator's next value is not ready
-    /// yet. Implementations will ensure that the current task will be notified
-    /// when the next value may be ready.
+    ///   yet. Implementations will ensure that the current task will be notified
+    ///   when the next value may be ready.
     ///
     /// - `Poll::Ready(Some(val))` means that the async iterator has successfully
-    /// produced a value, `val`, and may produce further values on subsequent
-    /// `poll_next` calls.
+    ///   produced a value, `val`, and may produce further values on subsequent
+    ///   `poll_next` calls.
     ///
     /// - `Poll::Ready(None)` means that the async iterator has terminated, and
-    /// `poll_next` should not be invoked again.
+    ///   `poll_next` should not be invoked again.
     ///
     /// # Panics
     ///
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 03b120fbf0c..1b9af10a6fd 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -381,7 +381,8 @@ pub struct AssertParamIsEq<T: Eq + PointeeSized> {
 ///
 /// assert_eq!(2.cmp(&1), Ordering::Greater);
 /// ```
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)]
+#[derive_const(PartialEq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 // This is a lang item only so that `BinOp::Cmp` in MIR can return it.
 // It has no special behavior, but does require that the three variants
@@ -1481,13 +1482,14 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
     }
 }
 
-fn default_chaining_impl<T: PointeeSized, U: PointeeSized>(
+fn default_chaining_impl<T, U>(
     lhs: &T,
     rhs: &U,
     p: impl FnOnce(Ordering) -> bool,
 ) -> ControlFlow<bool>
 where
-    T: PartialOrd<U>,
+    T: PartialOrd<U> + PointeeSized,
+    U: PointeeSized,
 {
     // It's important that this only call `partial_cmp` once, not call `eq` then
     // one of the relational operators.  We don't want to `bcmp`-then-`memcp` a
diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs
index a06a5227fe2..7d61c9345ec 100644
--- a/library/core/src/cmp/bytewise.rs
+++ b/library/core/src/cmp/bytewise.rs
@@ -17,11 +17,15 @@ use crate::num::NonZero;
 /// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct.
 /// - `<Self as PartialEq<Rhs>>::{eq,ne}` are equivalent to comparing the bytes.
 #[rustc_specialization_trait]
-pub(crate) unsafe trait BytewiseEq<Rhs = Self>: PartialEq<Rhs> + Sized {}
+#[const_trait]
+pub(crate) unsafe trait BytewiseEq<Rhs = Self>:
+    ~const PartialEq<Rhs> + Sized
+{
+}
 
 macro_rules! is_bytewise_comparable {
     ($($t:ty),+ $(,)?) => {$(
-        unsafe impl BytewiseEq for $t {}
+        unsafe impl const BytewiseEq for $t {}
     )+};
 }
 
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 881a7a24083..c43f3834630 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -135,16 +135,20 @@ pub enum FromBytesWithNulError {
 }
 
 #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl Error for FromBytesWithNulError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
+impl fmt::Display for FromBytesWithNulError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self::InteriorNul { .. } => "data provided contains an interior nul byte",
-            Self::NotNulTerminated => "data provided is not nul terminated",
+            Self::InteriorNul { position } => {
+                write!(f, "data provided contains an interior nul byte at byte position {position}")
+            }
+            Self::NotNulTerminated => write!(f, "data provided is not nul terminated"),
         }
     }
 }
 
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for FromBytesWithNulError {}
+
 /// An error indicating that no nul byte was present.
 ///
 /// A slice used to create a [`CStr`] must contain a nul byte somewhere
@@ -181,18 +185,6 @@ impl Default for &CStr {
     }
 }
 
-#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
-impl fmt::Display for FromBytesWithNulError {
-    #[allow(deprecated, deprecated_in_future)]
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(self.description())?;
-        if let Self::InteriorNul { position } = self {
-            write!(f, " at byte pos {position}")?;
-        }
-        Ok(())
-    }
-}
-
 impl CStr {
     /// Wraps a raw C string with a safe C string wrapper.
     ///
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 228a331e1da..8ac29e5b076 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -854,7 +854,6 @@ impl Display for Arguments<'_> {
 /// }";
 /// assert_eq!(format!("The origin is: {origin:#?}"), expected);
 /// ```
-
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index e1381ace441..7d41ae45093 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -358,7 +358,7 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    offset = _inner_slow_integer_to_str(self.unsigned_abs().$conv_fn(), &mut buf.buf);
+                    offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf);
                 }
                 // Only difference between signed and unsigned are these 4 lines.
                 if self < 0 {
@@ -401,7 +401,7 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    offset = _inner_slow_integer_to_str(self.$conv_fn(), &mut buf.buf);
+                    offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf);
                 }
                 // SAFETY: Starting from `offset`, all elements of the slice have been set.
                 unsafe { slice_buffer_to_str(&buf.buf, offset) }
@@ -412,7 +412,7 @@ macro_rules! impl_Display {
         )*
 
         #[cfg(feature = "optimize_for_size")]
-        fn _inner_slow_integer_to_str(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize {
+        fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize {
             let mut curr = buf.len();
 
             // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
@@ -437,7 +437,7 @@ macro_rules! impl_Display {
             const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1;
             let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
-            let offset = _inner_slow_integer_to_str(n, &mut buf);
+            let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf);
             // SAFETY: Starting from `offset`, all elements of the slice have been set.
             let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
             f.pad_integral(is_nonnegative, "", buf_slice)
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 1ece3d9bd5e..106cc725fee 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1379,6 +1379,7 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::floor`](../../std/primitive.f16.html#method.floor)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn floorf16(x: f16) -> f16;
@@ -1386,6 +1387,7 @@ pub const unsafe fn floorf16(x: f16) -> f16;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::floor`](../../std/primitive.f32.html#method.floor)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn floorf32(x: f32) -> f32;
@@ -1393,6 +1395,7 @@ pub const unsafe fn floorf32(x: f32) -> f32;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::floor`](../../std/primitive.f64.html#method.floor)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn floorf64(x: f64) -> f64;
@@ -1400,6 +1403,7 @@ pub const unsafe fn floorf64(x: f64) -> f64;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::floor`](../../std/primitive.f128.html#method.floor)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn floorf128(x: f128) -> f128;
@@ -1408,6 +1412,7 @@ pub const unsafe fn floorf128(x: f128) -> f128;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn ceilf16(x: f16) -> f16;
@@ -1415,6 +1420,7 @@ pub const unsafe fn ceilf16(x: f16) -> f16;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn ceilf32(x: f32) -> f32;
@@ -1422,6 +1428,7 @@ pub const unsafe fn ceilf32(x: f32) -> f32;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn ceilf64(x: f64) -> f64;
@@ -1429,6 +1436,7 @@ pub const unsafe fn ceilf64(x: f64) -> f64;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn ceilf128(x: f128) -> f128;
@@ -1437,6 +1445,7 @@ pub const unsafe fn ceilf128(x: f128) -> f128;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn truncf16(x: f16) -> f16;
@@ -1444,6 +1453,7 @@ pub const unsafe fn truncf16(x: f16) -> f16;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn truncf32(x: f32) -> f32;
@@ -1451,6 +1461,7 @@ pub const unsafe fn truncf32(x: f32) -> f32;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn truncf64(x: f64) -> f64;
@@ -1458,6 +1469,7 @@ pub const unsafe fn truncf64(x: f64) -> f64;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn truncf128(x: f128) -> f128;
@@ -1467,6 +1479,7 @@ pub const unsafe fn truncf128(x: f128) -> f128;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const fn round_ties_even_f16(x: f16) -> f16;
@@ -1476,6 +1489,7 @@ pub const fn round_ties_even_f16(x: f16) -> f16;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const fn round_ties_even_f32(x: f32) -> f32;
@@ -1485,6 +1499,7 @@ pub const fn round_ties_even_f32(x: f32) -> f32;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const fn round_ties_even_f64(x: f64) -> f64;
@@ -1494,6 +1509,7 @@ pub const fn round_ties_even_f64(x: f64) -> f64;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const fn round_ties_even_f128(x: f128) -> f128;
@@ -1502,6 +1518,7 @@ pub const fn round_ties_even_f128(x: f128) -> f128;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::round`](../../std/primitive.f16.html#method.round)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn roundf16(x: f16) -> f16;
@@ -1509,6 +1526,7 @@ pub const unsafe fn roundf16(x: f16) -> f16;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::round`](../../std/primitive.f32.html#method.round)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn roundf32(x: f32) -> f32;
@@ -1516,6 +1534,7 @@ pub const unsafe fn roundf32(x: f32) -> f32;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::round`](../../std/primitive.f64.html#method.round)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn roundf64(x: f64) -> f64;
@@ -1523,6 +1542,7 @@ pub const unsafe fn roundf64(x: f64) -> f64;
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::round`](../../std/primitive.f128.html#method.round)
+#[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
 pub const unsafe fn roundf128(x: f128) -> f128;
@@ -2208,6 +2228,7 @@ pub const unsafe fn raw_eq<T>(a: &T, b: &T) -> bool;
 /// [valid]: crate::ptr#safety
 #[rustc_nounwind]
 #[rustc_intrinsic]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 pub const unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32;
 
 /// See documentation of [`std::hint::black_box`] for details.
@@ -2533,6 +2554,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
     // Runtime NOP
 }
 
+#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[miri::intrinsic_fallback_is_spec]
+pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 {
+    // const eval overrides this function; at runtime, it is a NOP.
+    ptr
+}
+
 /// Returns whether we should perform contract-checking at runtime.
 ///
 /// This is meant to be similar to the ub_checks intrinsic, in terms
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index b5dfe6dbd71..088dea78129 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -149,7 +149,6 @@ impl<'data> BorrowedBuf<'data> {
     #[inline]
     pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
         BorrowedCursor {
-            start: self.filled,
             // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
             // lifetime covariantly is safe.
             buf: unsafe {
@@ -205,9 +204,6 @@ pub struct BorrowedCursor<'a> {
     // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into
     // it, so don't do that!
     buf: &'a mut BorrowedBuf<'a>,
-    /// The length of the filled portion of the underlying buffer at the time of the cursor's
-    /// creation.
-    start: usize,
 }
 
 impl<'a> BorrowedCursor<'a> {
@@ -225,7 +221,6 @@ impl<'a> BorrowedCursor<'a> {
                     self.buf,
                 )
             },
-            start: self.start,
         }
     }
 
@@ -235,23 +230,12 @@ impl<'a> BorrowedCursor<'a> {
         self.buf.capacity() - self.buf.filled
     }
 
-    /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`.
+    /// Returns the number of bytes written to the `BorrowedBuf` this cursor was created from.
     ///
-    /// Note that if this cursor is a reborrowed clone of another, then the count returned is the
-    /// count written via either cursor, not the count since the cursor was reborrowed.
+    /// In particular, the count returned is shared by all reborrows of the cursor.
     #[inline]
     pub fn written(&self) -> usize {
-        self.buf.filled - self.start
-    }
-
-    /// Returns a shared reference to the initialized portion of the cursor.
-    #[inline]
-    pub fn init_ref(&self) -> &[u8] {
-        // SAFETY: We only slice the initialized part of the buffer, which is always valid
-        unsafe {
-            let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init);
-            buf.assume_init_ref()
-        }
+        self.buf.filled
     }
 
     /// Returns a mutable reference to the initialized portion of the cursor.
@@ -264,15 +248,6 @@ impl<'a> BorrowedCursor<'a> {
         }
     }
 
-    /// Returns a mutable reference to the uninitialized part of the cursor.
-    ///
-    /// It is safe to uninitialize any of these bytes.
-    #[inline]
-    pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
-        // SAFETY: always in bounds
-        unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }
-    }
-
     /// Returns a mutable reference to the whole cursor.
     ///
     /// # Safety
@@ -325,7 +300,9 @@ impl<'a> BorrowedCursor<'a> {
     /// Initializes all bytes in the cursor.
     #[inline]
     pub fn ensure_init(&mut self) -> &mut Self {
-        let uninit = self.uninit_mut();
+        // SAFETY: always in bounds and we never uninitialize these bytes.
+        let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) };
+
         // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
         // since it is comes from a slice reference.
         unsafe {
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/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 3bc9cff8072..ab276500679 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -436,7 +436,6 @@ pub trait Extend<A> {
     /// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is,
     /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words,
     /// callers may assume that if they `extend_reserve`ed enough space they can call this method.
-
     // This method is for internal usage only. It is only on the trait because of specialization's limitations.
     #[unstable(feature = "extend_one_unchecked", issue = "none")]
     #[doc(hidden)]
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index f296792b1dc..10f9d464f7d 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -3414,10 +3414,10 @@ pub trait Iterator {
     /// ```
     #[stable(feature = "iter_copied", since = "1.36.0")]
     #[rustc_diagnostic_item = "iter_copied"]
-    fn copied<'a, T: 'a>(self) -> Copied<Self>
+    fn copied<'a, T>(self) -> Copied<Self>
     where
+        T: Copy + 'a,
         Self: Sized + Iterator<Item = &'a T>,
-        T: Copy,
     {
         Copied::new(self)
     }
@@ -3462,10 +3462,10 @@ pub trait Iterator {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "iter_cloned"]
-    fn cloned<'a, T: 'a>(self) -> Cloned<Self>
+    fn cloned<'a, T>(self) -> Cloned<Self>
     where
+        T: Clone + 'a,
         Self: Sized + Iterator<Item = &'a T>,
-        T: Clone,
     {
         Cloned::new(self)
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 2f701171505..3c33f4b1368 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -39,9 +39,9 @@
 //!   return. You should mark your implementation using `#[panic_handler]`.
 //!
 //! * `rust_eh_personality` - is used by the failure mechanisms of the
-//!    compiler. This is often mapped to GCC's personality function, but crates
-//!    which do not trigger a panic can be assured that this function is never
-//!    called. The `lang` attribute is called `eh_personality`.
+//!   compiler. This is often mapped to GCC's personality function, but crates
+//!   which do not trigger a panic can be assured that this function is never
+//!   called. The `lang` attribute is called `eh_personality`.
 
 #![stable(feature = "core", since = "1.6.0")]
 #![doc(
@@ -103,6 +103,7 @@
 #![feature(cfg_select)]
 #![feature(cfg_target_has_reliable_f16_f128)]
 #![feature(const_carrying_mul_add)]
+#![feature(const_cmp)]
 #![feature(const_destruct)]
 #![feature(const_eval_select)]
 #![feature(core_intrinsics)]
@@ -146,6 +147,7 @@
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
+#![feature(derive_const)]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
 #![feature(doc_notable_trait)]
@@ -160,6 +162,7 @@
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
 #![feature(macro_metavar_expr)]
+#![feature(macro_metavar_expr_concat)]
 #![feature(marker_trait_attr)]
 #![feature(min_specialization)]
 #![feature(multiple_supertrait_upcastable)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 1b6dbc2f428..8ac6ce2242d 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1615,7 +1615,7 @@ pub(crate) mod builtin {
     /// See [the reference] for more info.
     ///
     /// [the reference]: ../../../reference/attributes/derive.html
-    #[unstable(feature = "derive_const", issue = "none")]
+    #[unstable(feature = "derive_const", issue = "118304")]
     #[rustc_builtin_macro]
     pub macro derive_const($item:item) {
         /* compiler built-in */
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index fc35e54bb0d..34d8370da7e 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -1005,28 +1005,6 @@ impl<T> MaybeUninit<T> {
         }
     }
 
-    /// Deprecated version of [`slice::assume_init_ref`].
-    #[unstable(feature = "maybe_uninit_slice", issue = "63569")]
-    #[deprecated(
-        note = "replaced by inherent assume_init_ref method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
-        // SAFETY: Same for both methods.
-        unsafe { slice.assume_init_ref() }
-    }
-
-    /// Deprecated version of [`slice::assume_init_mut`].
-    #[unstable(feature = "maybe_uninit_slice", issue = "63569")]
-    #[deprecated(
-        note = "replaced by inherent assume_init_mut method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
-        // SAFETY: Same for both methods.
-        unsafe { slice.assume_init_mut() }
-    }
-
     /// Gets a pointer to the first element of the array.
     #[unstable(feature = "maybe_uninit_slice", issue = "63569")]
     #[inline(always)]
@@ -1040,94 +1018,6 @@ impl<T> MaybeUninit<T> {
     pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit<T>]) -> *mut T {
         this.as_mut_ptr() as *mut T
     }
-
-    /// Deprecated version of [`slice::write_copy_of_slice`].
-    #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
-    #[deprecated(
-        note = "replaced by inherent write_copy_of_slice method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn copy_from_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
-    where
-        T: Copy,
-    {
-        this.write_copy_of_slice(src)
-    }
-
-    /// Deprecated version of [`slice::write_clone_of_slice`].
-    #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
-    #[deprecated(
-        note = "replaced by inherent write_clone_of_slice method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn clone_from_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
-    where
-        T: Clone,
-    {
-        this.write_clone_of_slice(src)
-    }
-
-    /// Deprecated version of [`slice::write_filled`].
-    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
-    #[deprecated(
-        note = "replaced by inherent write_filled method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn fill<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a mut [T]
-    where
-        T: Clone,
-    {
-        this.write_filled(value)
-    }
-
-    /// Deprecated version of [`slice::write_with`].
-    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
-    #[deprecated(
-        note = "replaced by inherent write_with method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit<T>], mut f: F) -> &'a mut [T]
-    where
-        F: FnMut() -> T,
-    {
-        this.write_with(|_| f())
-    }
-
-    /// Deprecated version of [`slice::write_iter`].
-    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
-    #[deprecated(
-        note = "replaced by inherent write_iter method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn fill_from<'a, I>(
-        this: &'a mut [MaybeUninit<T>],
-        it: I,
-    ) -> (&'a mut [T], &'a mut [MaybeUninit<T>])
-    where
-        I: IntoIterator<Item = T>,
-    {
-        this.write_iter(it)
-    }
-
-    /// Deprecated version of [`slice::as_bytes`].
-    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
-    #[deprecated(
-        note = "replaced by inherent as_bytes method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>] {
-        this.as_bytes()
-    }
-
-    /// Deprecated version of [`slice::as_bytes_mut`].
-    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
-    #[deprecated(
-        note = "replaced by inherent as_bytes_mut method; will eventually be removed",
-        since = "1.83.0"
-    )]
-    pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>] {
-        this.as_bytes_mut()
-    }
 }
 
 impl<T> [MaybeUninit<T>] {
@@ -1304,7 +1194,7 @@ impl<T> [MaybeUninit<T>] {
     /// Fills a slice with elements returned by calling a closure for each index.
     ///
     /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use
-    /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can
+    /// [slice::write_filled]. If you want to use the `Default` trait to generate values, you can
     /// pass [`|_| Default::default()`][Default::default] as the argument.
     ///
     /// # Panics
@@ -1463,7 +1353,7 @@ impl<T> [MaybeUninit<T>] {
     /// use std::mem::MaybeUninit;
     ///
     /// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
-    /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
+    /// let uninit_bytes = uninit.as_bytes_mut();
     /// uninit_bytes.write_copy_of_slice(&[0x12, 0x34, 0x56, 0x78]);
     /// let vals = unsafe { uninit.assume_init_ref() };
     /// if cfg!(target_endian = "little") {
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 1bd12d818cf..2198d098c4b 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -36,7 +36,7 @@ pub use crate::intrinsics::transmute;
 /// * If you want to leak memory, see [`Box::leak`].
 /// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`].
 /// * If you want to dispose of a value properly, running its destructor, see
-/// [`mem::drop`].
+///   [`mem::drop`].
 ///
 /// # Safety
 ///
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index aaa68e8d7d1..49a7ae5de5c 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -787,7 +787,6 @@ impl Ipv4Addr {
     /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
     /// [unspecified address]: Ipv4Addr::UNSPECIFIED
     /// [broadcast address]: Ipv4Addr::BROADCAST
-
     ///
     /// # Examples
     ///
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 4c09c930c79..69e6c100e76 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -1448,7 +1448,6 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(self) -> f128 {
         // SAFETY: intrinsic with no preconditions
@@ -1478,7 +1477,6 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn ceil(self) -> f128 {
         // SAFETY: intrinsic with no preconditions
@@ -1514,7 +1512,6 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(self) -> f128 {
         // SAFETY: intrinsic with no preconditions
@@ -1548,7 +1545,6 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round_ties_even(self) -> f128 {
         intrinsics::round_ties_even_f128(self)
@@ -1580,7 +1576,6 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn trunc(self) -> f128 {
         // SAFETY: intrinsic with no preconditions
@@ -1611,7 +1606,6 @@ impl f128 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn fract(self) -> f128 {
         self - self.trunc()
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 1d98a485c4f..b66cef03d20 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -1424,7 +1424,6 @@ impl f16 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(self) -> f16 {
         // SAFETY: intrinsic with no preconditions
@@ -1454,7 +1453,6 @@ impl f16 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn ceil(self) -> f16 {
         // SAFETY: intrinsic with no preconditions
@@ -1490,7 +1488,6 @@ impl f16 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(self) -> f16 {
         // SAFETY: intrinsic with no preconditions
@@ -1524,7 +1521,6 @@ impl f16 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round_ties_even(self) -> f16 {
         intrinsics::round_ties_even_f16(self)
@@ -1556,7 +1552,6 @@ impl f16 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn trunc(self) -> f16 {
         // SAFETY: intrinsic with no preconditions
@@ -1587,7 +1582,6 @@ impl f16 {
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
-    // #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn fract(self) -> f16 {
         self - self.trunc()
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index b460c7d0205..f8344da79ad 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1591,7 +1591,6 @@ pub mod math {
     /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(x: f32) -> f32 {
         // SAFETY: intrinsic with no preconditions
@@ -1622,7 +1621,6 @@ pub mod math {
     #[doc(alias = "ceiling")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     pub const fn ceil(x: f32) -> f32 {
         // SAFETY: intrinsic with no preconditions
         unsafe { intrinsics::ceilf32(x) }
@@ -1657,7 +1655,6 @@ pub mod math {
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     pub const fn round(x: f32) -> f32 {
         // SAFETY: intrinsic with no preconditions
         unsafe { intrinsics::roundf32(x) }
@@ -1691,7 +1688,6 @@ pub mod math {
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     pub const fn round_ties_even(x: f32) -> f32 {
         intrinsics::round_ties_even_f32(x)
     }
@@ -1722,7 +1718,6 @@ pub mod math {
     #[doc(alias = "truncate")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     pub const fn trunc(x: f32) -> f32 {
         // SAFETY: intrinsic with no preconditions
         unsafe { intrinsics::truncf32(x) }
@@ -1752,7 +1747,6 @@ pub mod math {
     /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn fract(x: f32) -> f32 {
         x - trunc(x)
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 3cd079b84eb..93da63c896e 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1589,7 +1589,6 @@ pub mod math {
     /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(x: f64) -> f64 {
         // SAFETY: intrinsic with no preconditions
@@ -1619,7 +1618,6 @@ pub mod math {
     #[inline]
     #[doc(alias = "ceiling")]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn ceil(x: f64) -> f64 {
         // SAFETY: intrinsic with no preconditions
@@ -1654,7 +1652,6 @@ pub mod math {
     /// [`f64::round`]: ../../../std/primitive.f64.html#method.round
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(x: f64) -> f64 {
         // SAFETY: intrinsic with no preconditions
@@ -1688,7 +1685,6 @@ pub mod math {
     /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round_ties_even(x: f64) -> f64 {
         intrinsics::round_ties_even_f64(x)
@@ -1719,7 +1715,6 @@ pub mod math {
     #[inline]
     #[doc(alias = "truncate")]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn trunc(x: f64) -> f64 {
         // SAFETY: intrinsic with no preconditions
@@ -1750,7 +1745,6 @@ pub mod math {
     /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract
     #[inline]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn fract(x: f64) -> f64 {
         x - trunc(x)
diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs
index 28a3f5d880a..649a736b6e7 100644
--- a/library/core/src/num/int_log10.rs
+++ b/library/core/src/num/int_log10.rs
@@ -1,5 +1,5 @@
-/// These functions compute the integer logarithm of their type, assuming
-/// that someone has already checked that the value is strictly positive.
+//! These functions compute the integer logarithm of their type, assuming
+//! that someone has already checked that the value is strictly positive.
 
 // 0 < val <= u8::MAX
 #[inline]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 11d50e0f89f..b8900c4113a 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -200,9 +200,10 @@ impl<T> UseCloned for NonZero<T> where T: ZeroablePrimitive {}
 impl<T> Copy for NonZero<T> where T: ZeroablePrimitive {}
 
 #[stable(feature = "nonzero", since = "1.28.0")]
-impl<T> PartialEq for NonZero<T>
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const PartialEq for NonZero<T>
 where
-    T: ZeroablePrimitive + PartialEq,
+    T: ZeroablePrimitive + ~const PartialEq,
 {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index ab6823249c3..584cd60fbe5 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -556,7 +556,7 @@ macro_rules! uint_impl {
         pub const fn strict_add(self, rhs: Self) -> Self {
             let (a, b) = self.overflowing_add(rhs);
             if b { overflow_panic::add() } else { a }
-         }
+        }
 
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
         /// cannot occur.
@@ -653,7 +653,7 @@ macro_rules! uint_impl {
         pub const fn strict_add_signed(self, rhs: $SignedT) -> Self {
             let (a, b) = self.overflowing_add_signed(rhs);
             if b { overflow_panic::add() } else { a }
-         }
+        }
 
         /// Checked integer subtraction. Computes `self - rhs`, returning
         /// `None` if overflow occurred.
@@ -713,7 +713,7 @@ macro_rules! uint_impl {
         pub const fn strict_sub(self, rhs: Self) -> Self {
             let (a, b) = self.overflowing_sub(rhs);
             if b { overflow_panic::sub() } else { a }
-         }
+        }
 
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
         /// cannot occur.
@@ -805,6 +805,43 @@ macro_rules! uint_impl {
             }
         }
 
+        /// Strict subtraction with a signed integer. Computes `self - rhs`,
+        /// panicking if overflow occurred.
+        ///
+        /// # Panics
+        ///
+        /// ## Overflow behavior
+        ///
+        /// This function will always panic on overflow, regardless of whether overflow checks are enabled.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".strict_sub_signed(2), 1);")]
+        /// ```
+        ///
+        /// The following panic because of overflow:
+        ///
+        /// ```should_panic
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_sub_signed(2);")]
+        /// ```
+        ///
+        /// ```should_panic
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX).strict_sub_signed(-1);")]
+        /// ```
+        #[unstable(feature = "strict_overflow_ops", issue = "118260")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        #[track_caller]
+        pub const fn strict_sub_signed(self, rhs: $SignedT) -> Self {
+            let (a, b) = self.overflowing_sub_signed(rhs);
+            if b { overflow_panic::sub() } else { a }
+        }
+
         #[doc = concat!(
             "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`",
             stringify!($SignedT), "`], returning `None` if overflow occurred."
@@ -913,7 +950,7 @@ macro_rules! uint_impl {
         pub const fn strict_mul(self, rhs: Self) -> Self {
             let (a, b) = self.overflowing_mul(rhs);
             if b { overflow_panic::mul() } else { a }
-         }
+        }
 
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
         /// cannot occur.
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 9f432758a66..8036c59e893 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -577,6 +577,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::iter::{self, FusedIterator, TrustedLen};
+use crate::marker::Destruct;
 use crate::ops::{self, ControlFlow, Deref, DerefMut};
 use crate::panicking::{panic, panic_display};
 use crate::pin::Pin;
@@ -649,7 +650,8 @@ impl<T> Option<T> {
     #[must_use]
     #[inline]
     #[stable(feature = "is_some_and", since = "1.70.0")]
-    pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn is_some_and(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool {
         match self {
             None => false,
             Some(x) => f(x),
@@ -697,7 +699,8 @@ impl<T> Option<T> {
     #[must_use]
     #[inline]
     #[stable(feature = "is_none_or", since = "1.82.0")]
-    pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn is_none_or(self, f: impl ~const FnOnce(T) -> bool + ~const Destruct) -> bool {
         match self {
             None => true,
             Some(x) => f(x),
@@ -1023,7 +1026,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or(self, default: T) -> T {
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn unwrap_or(self, default: T) -> T
+    where
+        T: ~const Destruct,
+    {
         match self {
             Some(x) => x,
             None => default,
@@ -1042,9 +1050,10 @@ impl<T> Option<T> {
     #[inline]
     #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or_else<F>(self, f: F) -> T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn unwrap_or_else<F>(self, f: F) -> T
     where
-        F: FnOnce() -> T,
+        F: ~const FnOnce() -> T + ~const Destruct,
     {
         match self {
             Some(x) => x,
@@ -1073,9 +1082,10 @@ impl<T> Option<T> {
     /// [`FromStr`]: crate::str::FromStr
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or_default(self) -> T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn unwrap_or_default(self) -> T
     where
-        T: Default,
+        T: ~const Default,
     {
         match self {
             Some(x) => x,
@@ -1139,9 +1149,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map<U, F>(self, f: F) -> Option<U>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map<U, F>(self, f: F) -> Option<U>
     where
-        F: FnOnce(T) -> U,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
     {
         match self {
             Some(x) => Some(f(x)),
@@ -1169,7 +1180,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "result_option_inspect", since = "1.76.0")]
-    pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn inspect<F>(self, f: F) -> Self
+    where
+        F: ~const FnOnce(&T) + ~const Destruct,
+    {
         if let Some(ref x) = self {
             f(x);
         }
@@ -1198,9 +1213,11 @@ impl<T> Option<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "if you don't need the returned value, use `if let` instead"]
-    pub fn map_or<U, F>(self, default: U, f: F) -> U
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map_or<U, F>(self, default: U, f: F) -> U
     where
-        F: FnOnce(T) -> U,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
+        U: ~const Destruct,
     {
         match self {
             Some(t) => f(t),
@@ -1243,10 +1260,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
     where
-        D: FnOnce() -> U,
-        F: FnOnce(T) -> U,
+        D: ~const FnOnce() -> U + ~const Destruct,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
     {
         match self {
             Some(t) => f(t),
@@ -1273,10 +1291,11 @@ impl<T> Option<T> {
     /// [default value]: Default::default
     #[inline]
     #[unstable(feature = "result_option_map_or_default", issue = "138099")]
-    pub fn map_or_default<U, F>(self, f: F) -> U
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn map_or_default<U, F>(self, f: F) -> U
     where
-        U: Default,
-        F: FnOnce(T) -> U,
+        U: ~const Default,
+        F: ~const FnOnce(T) -> U + ~const Destruct,
     {
         match self {
             Some(t) => f(t),
@@ -1307,7 +1326,8 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn ok_or<E: ~const Destruct>(self, err: E) -> Result<T, E> {
         match self {
             Some(v) => Ok(v),
             None => Err(err),
@@ -1332,9 +1352,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
     where
-        F: FnOnce() -> E,
+        F: ~const FnOnce() -> E + ~const Destruct,
     {
         match self {
             Some(v) => Ok(v),
@@ -1463,7 +1484,12 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and<U>(self, optb: Option<U>) -> Option<U> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn and<U>(self, optb: Option<U>) -> Option<U>
+    where
+        T: ~const Destruct,
+        U: ~const Destruct,
+    {
         match self {
             Some(_) => optb,
             None => None,
@@ -1502,9 +1528,10 @@ impl<T> Option<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_confusables("flat_map", "flatmap")]
-    pub fn and_then<U, F>(self, f: F) -> Option<U>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn and_then<U, F>(self, f: F) -> Option<U>
     where
-        F: FnOnce(T) -> Option<U>,
+        F: ~const FnOnce(T) -> Option<U> + ~const Destruct,
     {
         match self {
             Some(x) => f(x),
@@ -1538,9 +1565,11 @@ impl<T> Option<T> {
     /// [`Some(t)`]: Some
     #[inline]
     #[stable(feature = "option_filter", since = "1.27.0")]
-    pub fn filter<P>(self, predicate: P) -> Self
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn filter<P>(self, predicate: P) -> Self
     where
-        P: FnOnce(&T) -> bool,
+        P: ~const FnOnce(&T) -> bool + ~const Destruct,
+        T: ~const Destruct,
     {
         if let Some(x) = self {
             if predicate(&x) {
@@ -1579,7 +1608,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or(self, optb: Option<T>) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn or(self, optb: Option<T>) -> Option<T>
+    where
+        T: ~const Destruct,
+    {
         match self {
             x @ Some(_) => x,
             None => optb,
@@ -1601,9 +1634,13 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or_else<F>(self, f: F) -> Option<T>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn or_else<F>(self, f: F) -> Option<T>
     where
-        F: FnOnce() -> Option<T>,
+        F: ~const FnOnce() -> Option<T> + ~const Destruct,
+        //FIXME(const_hack): this `T: ~const Destruct` is unnecessary, but even precise live drops can't tell
+        // no value of type `T` gets dropped here
+        T: ~const Destruct,
     {
         match self {
             x @ Some(_) => x,
@@ -1634,7 +1671,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_xor", since = "1.37.0")]
-    pub fn xor(self, optb: Option<T>) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn xor(self, optb: Option<T>) -> Option<T>
+    where
+        T: ~const Destruct,
+    {
         match (self, optb) {
             (a @ Some(_), None) => a,
             (None, b @ Some(_)) => b,
@@ -1668,7 +1709,11 @@ impl<T> Option<T> {
     #[must_use = "if you intended to set a value, consider assignment instead"]
     #[inline]
     #[stable(feature = "option_insert", since = "1.53.0")]
-    pub fn insert(&mut self, value: T) -> &mut T {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn insert(&mut self, value: T) -> &mut T
+    where
+        T: ~const Destruct,
+    {
         *self = Some(value);
 
         // SAFETY: the code above just filled the option
@@ -1720,9 +1765,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_get_or_insert_default", since = "1.83.0")]
-    pub fn get_or_insert_default(&mut self) -> &mut T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn get_or_insert_default(&mut self) -> &mut T
     where
-        T: Default,
+        T: ~const Default + ~const Destruct,
     {
         self.get_or_insert_with(T::default)
     }
@@ -1746,9 +1792,11 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
-    pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
     where
-        F: FnOnce() -> T,
+        F: ~const FnOnce() -> T + ~const Destruct,
+        T: ~const Destruct,
     {
         if let None = self {
             *self = Some(f());
@@ -1812,9 +1860,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "option_take_if", since = "1.80.0")]
-    pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn take_if<P>(&mut self, predicate: P) -> Option<T>
     where
-        P: FnOnce(&mut T) -> bool,
+        P: ~const FnOnce(&mut T) -> bool + ~const Destruct,
     {
         if self.as_mut().map_or(false, predicate) { self.take() } else { None }
     }
@@ -1859,7 +1908,12 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip(z), None);
     /// ```
     #[stable(feature = "option_zip_option", since = "1.46.0")]
-    pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
+    where
+        T: ~const Destruct,
+        U: ~const Destruct,
+    {
         match (self, other) {
             (Some(a), Some(b)) => Some((a, b)),
             _ => None,
@@ -1895,9 +1949,12 @@ impl<T> Option<T> {
     /// assert_eq!(x.zip_with(None, Point::new), None);
     /// ```
     #[unstable(feature = "option_zip", issue = "70086")]
-    pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
+    #[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
+    pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
     where
-        F: FnOnce(T, U) -> R,
+        F: ~const FnOnce(T, U) -> R + ~const Destruct,
+        T: ~const Destruct,
+        U: ~const Destruct,
     {
         match (self, other) {
             (Some(a), Some(b)) => Some(f(a, b)),
@@ -2243,7 +2300,8 @@ impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> crate::marker::StructuralPartialEq for Option<T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialEq> PartialEq for Option<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: ~const PartialEq> const PartialEq for Option<T> {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
         // Spelling out the cases explicitly optimizes better than
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 7b9e04920d5..a4be66b90ca 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -80,7 +80,7 @@ pub use crate::macros::builtin::{
     alloc_error_handler, bench, derive, global_allocator, test, test_case,
 };
 
-#[unstable(feature = "derive_const", issue = "none")]
+#[unstable(feature = "derive_const", issue = "118304")]
 pub use crate::macros::builtin::derive_const;
 
 #[unstable(
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 5bd80149a1d..9a1ba7d1728 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1363,7 +1363,6 @@ mod prim_f16 {}
 /// x = a + b + c + d; // As written
 /// x = (a + c) + (b + d); // Reordered to shorten critical path and enable vectorization
 /// ```
-
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f32 {}
 
diff --git a/library/core/src/ptr/docs/as_uninit_slice.md b/library/core/src/ptr/docs/as_uninit_slice.md
index c80c0405883..1113f4748c2 100644
--- a/library/core/src/ptr/docs/as_uninit_slice.md
+++ b/library/core/src/ptr/docs/as_uninit_slice.md
@@ -10,24 +10,24 @@ When calling this method, you have to ensure that *either* the pointer is null *
 all of the following is true:
 
 * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
-and it must be properly aligned. This means in particular:
+  and it must be properly aligned. This means in particular:
 
 * The entire memory range of this slice must be contained within a single [allocation]!
-Slices can never span across multiple allocations.
+  Slices can never span across multiple allocations.
 
 * The pointer must be aligned even for zero-length slices. One
-reason for this is that enum layout optimizations may rely on references
-(including slices of any length) being aligned and non-null to distinguish
-them from other data. You can obtain a pointer that is usable as `data`
-for zero-length slices using [`NonNull::dangling()`].
+  reason for this is that enum layout optimizations may rely on references
+  (including slices of any length) being aligned and non-null to distinguish
+  them from other data. You can obtain a pointer that is usable as `data`
+  for zero-length slices using [`NonNull::dangling()`].
 
 * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-See the safety documentation of [`pointer::offset`].
+  See the safety documentation of [`pointer::offset`].
 
 * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
-arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-In particular, while this reference exists, the memory the pointer points to must
-not get mutated (except inside `UnsafeCell`).
+  arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+  In particular, while this reference exists, the memory the pointer points to must
+  not get mutated (except inside `UnsafeCell`).
 
 This applies even if the result of this method is unused!
 
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index fe8c6f83034..dbe3999b4a4 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -28,7 +28,8 @@
 //!   undefined behavior to perform two concurrent accesses to the same location from different
 //!   threads unless both accesses only read from memory. Notice that this explicitly
 //!   includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot
-//!   be used for inter-thread synchronization.
+//!   be used for inter-thread synchronization, regardless of whether they are acting on
+//!   Rust memory or not.
 //! * The result of casting a reference to a pointer is valid for as long as the
 //!   underlying allocation is live and no reference (just raw pointers) is used to
 //!   access the same memory. That is, reference and pointer accesses cannot be
@@ -114,6 +115,10 @@
 //! fully contiguous (i.e., has no "holes"), there is no guarantee that this
 //! will not change in the future.
 //!
+//! Allocations must behave like "normal" memory: in particular, reads must not have
+//! side-effects, and writes must become visible to other threads using the usual synchronization
+//! primitives.
+//!
 //! For any allocation with `base` address, `size`, and a set of
 //! `addresses`, the following are guaranteed:
 //! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
@@ -2021,54 +2026,61 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
     }
 }
 
-/// Performs a volatile read of the value from `src` without moving it. This
-/// leaves the memory in `src` unchanged.
-///
-/// Volatile operations are intended to act on I/O memory, and are guaranteed
-/// to not be elided or reordered by the compiler across other volatile
-/// operations.
-///
-/// # Notes
-///
-/// Rust does not currently have a rigorously and formally defined memory model,
-/// so the precise semantics of what "volatile" means here is subject to change
-/// over time. That being said, the semantics will almost always end up pretty
-/// similar to [C11's definition of volatile][c11].
-///
-/// The compiler shouldn't change the relative order or number of volatile
-/// memory operations. However, volatile memory operations on zero-sized types
-/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops
-/// and may be ignored.
-///
-/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
+/// Performs a volatile read of the value from `src` without moving it.
+///
+/// Volatile operations are intended to act on I/O memory. As such, they are considered externally
+/// observable events (just like syscalls, but less opaque), and are guaranteed to not be elided or
+/// reordered by the compiler across other externally observable events. With this in mind, there
+/// are two cases of usage that need to be distinguished:
+///
+/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like
+///   [`read`], except for the additional guarantee that it won't be elided or reordered (see
+///   above). This implies that the operation will actually access memory and not e.g. be lowered to
+///   reusing data from a previous read. Other than that, all the usual rules for memory accesses
+///   apply (including provenance).  In particular, just like in C, whether an operation is volatile
+///   has no bearing whatsoever on questions involving concurrent accesses from multiple threads.
+///   Volatile accesses behave exactly like non-atomic accesses in that regard.
+///
+/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust
+///   allocation. In this use-case, the pointer does *not* have to be [valid] for reads. This is
+///   typically used for CPU and peripheral registers that must be accessed via an I/O memory
+///   mapping, most commonly at fixed addresses reserved by the hardware. These often have special
+///   semantics associated to their manipulation, and cannot be used as general purpose memory.
+///   Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics
+///   of such a read are well-defined by the target hardware. The provenance of the pointer is
+///   irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It
+///   can cause side-effects, but those must not affect Rust-allocated memory in any way. This
+///   access is still not considered [atomic], and as such it cannot be used for inter-thread
+///   synchronization.
+///
+/// Note that volatile memory operations where T is a zero-sized type are noops and may be ignored.
+///
+/// [allocation]: crate::ptr#allocated-object
+/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses
 ///
 /// # Safety
 ///
+/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of whether `T` is
+/// [`Copy`]. If `T` is not [`Copy`], using both the returned value and the value at `*src` can
+/// [violate memory safety][read-ownership]. However, storing non-[`Copy`] types in volatile memory
+/// is almost certainly incorrect.
+///
 /// Behavior is undefined if any of the following conditions are violated:
 ///
-/// * `src` must be [valid] for reads.
+/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust
+///   allocations and reading from that memory must:
+///   - not trap, and
+///   - not cause any memory inside a Rust allocation to be modified.
 ///
 /// * `src` must be properly aligned.
 ///
-/// * `src` must point to a properly initialized value of type `T`.
-///
-/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of
-/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
-/// value and the value at `*src` can [violate memory safety][read-ownership].
-/// However, storing non-[`Copy`] types in volatile memory is almost certainly
-/// incorrect.
+/// * Reading from `src` must produce a properly initialized value of type `T`.
 ///
 /// Note that even if `T` has size `0`, the pointer must be properly aligned.
 ///
 /// [valid]: self#safety
 /// [read-ownership]: read#ownership-of-the-returned-value
 ///
-/// Just like in C, whether an operation is volatile has no bearing whatsoever
-/// on questions involving concurrent access from multiple threads. Volatile
-/// accesses behave exactly like non-atomic accesses in that regard. In particular,
-/// a race between a `read_volatile` and any write operation to the same location
-/// is undefined behavior.
-///
 /// # Examples
 ///
 /// Basic usage:
@@ -2090,50 +2102,63 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
     unsafe {
         ub_checks::assert_unsafe_precondition!(
             check_language_ub,
-            "ptr::read_volatile requires that the pointer argument is aligned and non-null",
+            "ptr::read_volatile requires that the pointer argument is aligned",
             (
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
-                is_zst: bool = T::IS_ZST,
-            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned(addr, align)
         );
         intrinsics::volatile_load(src)
     }
 }
 
-/// Performs a volatile write of a memory location with the given value without
-/// reading or dropping the old value.
-///
-/// Volatile operations are intended to act on I/O memory, and are guaranteed
-/// to not be elided or reordered by the compiler across other volatile
-/// operations.
-///
-/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
-/// could leak allocations or resources, so care should be taken not to overwrite
-/// an object that should be dropped.
-///
-/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
-/// location pointed to by `dst`.
-///
-/// # Notes
-///
-/// Rust does not currently have a rigorously and formally defined memory model,
-/// so the precise semantics of what "volatile" means here is subject to change
-/// over time. That being said, the semantics will almost always end up pretty
-/// similar to [C11's definition of volatile][c11].
-///
-/// The compiler shouldn't change the relative order or number of volatile
-/// memory operations. However, volatile memory operations on zero-sized types
-/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops
-/// and may be ignored.
-///
-/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
+/// Performs a volatile write of a memory location with the given value without reading or dropping
+/// the old value.
+///
+/// Volatile operations are intended to act on I/O memory. As such, they are considered externally
+/// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the
+/// compiler across other externally observable events. With this in mind, there are two cases of
+/// usage that need to be distinguished:
+///
+/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like
+///   [`write`][write()], except for the additional guarantee that it won't be elided or reordered
+///   (see above). This implies that the operation will actually access memory and not e.g. be
+///   lowered to a register access. Other than that, all the usual rules for memory accesses apply
+///   (including provenance). In particular, just like in C, whether an operation is volatile has no
+///   bearing whatsoever on questions involving concurrent access from multiple threads. Volatile
+///   accesses behave exactly like non-atomic accesses in that regard.
+///
+/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust
+///   allocation. In this use-case, the pointer does *not* have to be [valid] for writes. This is
+///   typically used for CPU and peripheral registers that must be accessed via an I/O memory
+///   mapping, most commonly at fixed addresses reserved by the hardware. These often have special
+///   semantics associated to their manipulation, and cannot be used as general purpose memory.
+///   Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics
+///   of such a write are well-defined by the target hardware. The provenance of the pointer is
+///   irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It
+///   can cause side-effects, but those must not affect Rust-allocated memory in any way. This
+///   access is still not considered [atomic], and as such it cannot be used for inter-thread
+///   synchronization.
+///
+/// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed
+/// to `write_volatile`) are noops and may be ignored.
+///
+/// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care should be taken not to overwrite an object that should be
+/// dropped when operating on Rust memory. Additionally, it does not drop `src`. Semantically, `src`
+/// is moved into the location pointed to by `dst`.
+///
+/// [allocation]: crate::ptr#allocated-object
+/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses
 ///
 /// # Safety
 ///
 /// Behavior is undefined if any of the following conditions are violated:
 ///
-/// * `dst` must be [valid] for writes.
+/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust
+///   allocations and writing to that memory must:
+///   - not trap, and
+///   - not cause any memory inside a Rust allocation to be modified.
 ///
 /// * `dst` must be properly aligned.
 ///
@@ -2141,12 +2166,6 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// [valid]: self#safety
 ///
-/// Just like in C, whether an operation is volatile has no bearing whatsoever
-/// on questions involving concurrent access from multiple threads. Volatile
-/// accesses behave exactly like non-atomic accesses in that regard. In particular,
-/// a race between a `write_volatile` and any other operation (reading or writing)
-/// on the same location is undefined behavior.
-///
 /// # Examples
 ///
 /// Basic usage:
@@ -2170,12 +2189,11 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     unsafe {
         ub_checks::assert_unsafe_precondition!(
             check_language_ub,
-            "ptr::write_volatile requires that the pointer argument is aligned and non-null",
+            "ptr::write_volatile requires that the pointer argument is aligned",
             (
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
-                is_zst: bool = T::IS_ZST,
-            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned(addr, align)
         );
         intrinsics::volatile_store(dst, src);
     }
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 5ce72b46eee..1eda8bc1bec 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -8,9 +8,10 @@ use crate::num::NonZero;
 use crate::ops::ControlFlow;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U> PartialEq<[U]> for [T]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U> const PartialEq<[U]> for [T]
 where
-    T: PartialEq<U>,
+    T: ~const PartialEq<U>,
 {
     fn eq(&self, other: &[U]) -> bool {
         SlicePartialEq::equal(self, other)
@@ -94,6 +95,8 @@ impl<T: PartialOrd> PartialOrd for [T] {
 
 #[doc(hidden)]
 // intermediate trait for specialization of slice's PartialEq
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 trait SlicePartialEq<B> {
     fn equal(&self, other: &[B]) -> bool;
 
@@ -103,9 +106,10 @@ trait SlicePartialEq<B> {
 }
 
 // Generic slice equality
-impl<A, B> SlicePartialEq<B> for [A]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A, B> const SlicePartialEq<B> for [A]
 where
-    A: PartialEq<B>,
+    A: ~const PartialEq<B>,
 {
     default fn equal(&self, other: &[B]) -> bool {
         if self.len() != other.len() {
@@ -115,11 +119,14 @@ where
         // Implemented as explicit indexing rather
         // than zipped iterators for performance reasons.
         // See PR https://github.com/rust-lang/rust/pull/116846
-        for idx in 0..self.len() {
+        // FIXME(const_hack): make this a `for idx in 0..self.len()` loop.
+        let mut idx = 0;
+        while idx < self.len() {
             // bound checks are optimized away
             if self[idx] != other[idx] {
                 return false;
             }
+            idx += 1;
         }
 
         true
@@ -128,9 +135,10 @@ where
 
 // When each element can be compared byte-wise, we can compare all the bytes
 // from the whole size in one call to the intrinsics.
-impl<A, B> SlicePartialEq<B> for [A]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A, B> const SlicePartialEq<B> for [A]
 where
-    A: BytewiseEq<B>,
+    A: ~const BytewiseEq<B>,
 {
     fn equal(&self, other: &[B]) -> bool {
         if self.len() != other.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/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 18a516c0f60..029abf17539 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -2651,7 +2651,6 @@ impl str {
     /// you're trying to parse into.
     ///
     /// `parse` can parse into any type that implements the [`FromStr`] trait.
-
     ///
     /// # Errors
     ///
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 42ffc591b5b..d0f2b9226bf 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -23,7 +23,8 @@ impl Ord for str {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl PartialEq for str {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl const PartialEq for str {
     #[inline]
     fn eq(&self, other: &str) -> bool {
         self.as_bytes() == other.as_bytes()
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index a7caaeb95cd..b809294cfce 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -121,12 +121,24 @@ pub(crate) const fn maybe_is_aligned_and_not_null(
     is_zst: bool,
 ) -> bool {
     // This is just for safety checks so we can const_eval_select.
+    maybe_is_aligned(ptr, align) && (is_zst || !ptr.is_null())
+}
+
+/// Checks whether `ptr` is properly aligned with respect to the given alignment.
+///
+/// In `const` this is approximate and can fail spuriously. It is primarily intended
+/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
+/// check is anyway not executed in `const`.
+#[inline]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+pub(crate) const fn maybe_is_aligned(ptr: *const (), align: usize) -> bool {
+    // This is just for safety checks so we can const_eval_select.
     const_eval_select!(
-        @capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
+        @capture { ptr: *const (), align: usize } -> bool:
         if const {
-            is_zst || !ptr.is_null()
+            true
         } else {
-            ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
+            ptr.is_aligned_to(align)
         }
     )
 }
diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs
index 73dbfaf5ee9..4074148436c 100644
--- a/library/coretests/tests/io/borrowed_buf.rs
+++ b/library/coretests/tests/io/borrowed_buf.rs
@@ -61,7 +61,7 @@ fn clear() {
     assert_eq!(rbuf.filled().len(), 0);
     assert_eq!(rbuf.unfilled().capacity(), 16);
 
-    assert_eq!(rbuf.unfilled().init_ref(), [255; 16]);
+    assert_eq!(rbuf.unfilled().init_mut(), [255; 16]);
 }
 
 #[test]
@@ -124,7 +124,7 @@ fn reborrow_written() {
     assert_eq!(cursor2.written(), 32);
     assert_eq!(cursor.written(), 32);
 
-    assert_eq!(buf.unfilled().written(), 0);
+    assert_eq!(buf.unfilled().written(), 32);
     assert_eq!(buf.init_len(), 32);
     assert_eq!(buf.filled().len(), 32);
     let filled = buf.filled();
@@ -142,9 +142,7 @@ fn cursor_set_init() {
     }
 
     assert_eq!(rbuf.init_len(), 8);
-    assert_eq!(rbuf.unfilled().init_ref().len(), 8);
     assert_eq!(rbuf.unfilled().init_mut().len(), 8);
-    assert_eq!(rbuf.unfilled().uninit_mut().len(), 8);
     assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16);
 
     rbuf.unfilled().advance(4);
@@ -160,9 +158,7 @@ fn cursor_set_init() {
     }
 
     assert_eq!(rbuf.init_len(), 12);
-    assert_eq!(rbuf.unfilled().init_ref().len(), 8);
     assert_eq!(rbuf.unfilled().init_mut().len(), 8);
-    assert_eq!(rbuf.unfilled().uninit_mut().len(), 4);
     assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12);
 }
 
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/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index e2249bd7f6a..4cfac9ecc2a 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -19,7 +19,6 @@
 #![feature(const_deref)]
 #![feature(const_destruct)]
 #![feature(const_eval_select)]
-#![feature(const_float_round_methods)]
 #![feature(const_ops)]
 #![feature(const_ref_cell)]
 #![feature(const_trait_impl)]
diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml
index 8ea92088a84..0042a6e8ece 100644
--- a/library/proc_macro/Cargo.toml
+++ b/library/proc_macro/Cargo.toml
@@ -9,7 +9,7 @@ std = { path = "../std" }
 # `core` when resolving doc links. Without this line a different `core` will be
 # loaded from sysroot causing duplicate lang items and other similar errors.
 core = { path = "../core" }
-rustc-literal-escaper = { version = "0.0.4", features = ["rustc-dep-of-std"] }
+rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] }
 
 [features]
 default = ["rustc-dep-of-std"]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index ff326342989..162b4fdcc8a 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1471,11 +1471,11 @@ impl Literal {
                 let mut error = None;
                 let mut buf = Vec::with_capacity(symbol.len());
 
-                unescape_c_str(symbol, |_span, c| match c {
+                unescape_c_str(symbol, |_span, res| match res {
                     Ok(MixedUnit::Char(c)) => {
-                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                        buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes())
                     }
-                    Ok(MixedUnit::HighByte(b)) => buf.push(b),
+                    Ok(MixedUnit::HighByte(b)) => buf.push(b.get()),
                     Err(err) => {
                         if err.is_fatal() {
                             error = Some(ConversionErrorKind::FailedToUnescape(err));
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 86d23df5238..5c3132a7375 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -23,7 +23,7 @@ unwind = { path = "../unwind" }
 hashbrown = { version = "0.15", default-features = false, features = [
     'rustc-dep-of-std',
 ] }
-std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [
+std_detect = { path = "../stdarch/crates/std_detect", public = true, default-features = false, features = [
     'rustc-dep-of-std',
 ] }
 
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 17c32d7a571..d351ee5e739 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -489,7 +489,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
             }
         };
 
-        let unfilled_but_initialized = cursor.init_ref().len();
+        let unfilled_but_initialized = cursor.init_mut().len();
         let bytes_read = cursor.written();
         let was_fully_initialized = read_buf.init_len() == buf_len;
 
@@ -3053,7 +3053,7 @@ impl<T: Read> Read for Take<T> {
             // The condition above guarantees that `self.limit` fits in `usize`.
             let limit = self.limit as usize;
 
-            let extra_init = cmp::min(limit, buf.init_ref().len());
+            let extra_init = cmp::min(limit, buf.init_mut().len());
 
             // SAFETY: no uninit data is written to ibuf
             let ibuf = unsafe { &mut buf.as_mut()[..limit] };
@@ -3068,7 +3068,7 @@ impl<T: Read> Read for Take<T> {
             let mut cursor = sliced_buf.unfilled();
             let result = self.inner.read_buf(cursor.reborrow());
 
-            let new_init = cursor.init_ref().len();
+            let new_init = cursor.init_mut().len();
             let filled = sliced_buf.len();
 
             // cursor / sliced_buf / ibuf must drop here
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 311b2cb9323..323742a75b0 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -329,7 +329,6 @@
 #![feature(bstr_internals)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
-#![feature(const_float_round_methods)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(duration_constants)]
diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs
index e79ec2ae966..2bff73add33 100644
--- a/library/std/src/num/f32.rs
+++ b/library/std/src/num/f32.rs
@@ -44,7 +44,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn floor(self) -> f32 {
         core::f32::math::floor(self)
@@ -67,7 +67,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn ceil(self) -> f32 {
         core::f32::math::ceil(self)
@@ -96,7 +96,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn round(self) -> f32 {
         core::f32::math::round(self)
@@ -123,7 +123,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "round_ties_even", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn round_ties_even(self) -> f32 {
         core::f32::math::round_ties_even(self)
@@ -149,7 +149,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trunc(self) -> f32 {
         core::f32::math::trunc(self)
@@ -173,7 +173,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn fract(self) -> f32 {
         core::f32::math::fract(self)
diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs
index 853417825f9..b71e319f407 100644
--- a/library/std/src/num/f64.rs
+++ b/library/std/src/num/f64.rs
@@ -44,7 +44,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn floor(self) -> f64 {
         core::f64::math::floor(self)
@@ -67,7 +67,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn ceil(self) -> f64 {
         core::f64::math::ceil(self)
@@ -96,7 +96,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn round(self) -> f64 {
         core::f64::math::round(self)
@@ -123,7 +123,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "round_ties_even", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn round_ties_even(self) -> f64 {
         core::f64::math::round_ties_even(self)
@@ -149,7 +149,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trunc(self) -> f64 {
         core::f64::math::trunc(self)
@@ -173,7 +173,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_round_methods", issue = "141555")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn fract(self) -> f64 {
         core::f64::math::fract(self)
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 69f03353153..70c11131556 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -67,7 +67,7 @@ pub use core::prelude::v1::{
     alloc_error_handler, bench, derive, global_allocator, test, test_case,
 };
 
-#[unstable(feature = "derive_const", issue = "none")]
+#[unstable(feature = "derive_const", issue = "118304")]
 pub use core::prelude::v1::derive_const;
 
 // Do not `doc(no_inline)` either.
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index 571f0d14248..0c05f152ef8 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -10,7 +10,7 @@
 //! (some invariant is not being upheld).
 //!
 //! The specifics of how this "poisoned" state affects other threads
-//! depend on the primitive. See [#Overview] bellow.
+//! depend on the primitive. See [#Overview] below.
 //!
 //! For the alternative implementations that do not employ poisoning,
 //! see `std::sync::nonpoisoning`.
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index eee169d410a..edac5262a4e 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -197,7 +197,7 @@ compat_fn_optional! {
     pub fn WakeByAddressSingle(address: *const c_void);
 }
 
-#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))]
+#[cfg(any(target_vendor = "win7"))]
 compat_fn_with_fallback! {
     pub static NTDLL: &CStr = c"ntdll";
 
@@ -228,65 +228,14 @@ compat_fn_with_fallback! {
     ) -> NTSTATUS {
         panic!("keyed events not available")
     }
+}
 
-    // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically.
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtCreateFile(
-        filehandle: *mut HANDLE,
-        desiredaccess: FILE_ACCESS_RIGHTS,
-        objectattributes: *const OBJECT_ATTRIBUTES,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        allocationsize: *const i64,
-        fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
-        shareaccess: FILE_SHARE_MODE,
-        createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
-        createoptions: NTCREATEFILE_CREATE_OPTIONS,
-        eabuffer: *const c_void,
-        ealength: u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtOpenFile(
-        filehandle: *mut HANDLE,
-        desiredaccess: u32,
-        objectattributes: *const OBJECT_ATTRIBUTES,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        shareaccess: u32,
-        openoptions: u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtReadFile(
-        filehandle: HANDLE,
-        event: HANDLE,
-        apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const c_void,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *mut c_void,
-        length: u32,
-        byteoffset: *const i64,
-        key: *const u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn NtWriteFile(
-        filehandle: HANDLE,
-        event: HANDLE,
-        apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const c_void,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *const c_void,
-        length: u32,
-        byteoffset: *const i64,
-        key: *const u32
-    ) -> NTSTATUS {
-        STATUS_NOT_IMPLEMENTED
-    }
-    #[cfg(target_vendor = "uwp")]
-    pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 {
-        Status as u32
+cfg_if::cfg_if! {
+    if #[cfg(target_vendor = "uwp")] {
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
+        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
     }
 }
diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs
index bce54c5ffce..9e82e6a7200 100644
--- a/library/windows_targets/src/lib.rs
+++ b/library/windows_targets/src/lib.rs
@@ -7,8 +7,7 @@
 #![feature(decl_macro)]
 #![feature(no_core)]
 
-#[cfg(feature = "windows_raw_dylib")]
-pub macro link {
+pub macro link_raw_dylib {
     ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
         #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))]
         #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))]
@@ -18,6 +17,26 @@ pub macro link {
         }
     )
 }
+
+pub macro link_dylib {
+    ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
+        // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't
+        // have in this repo. So instead we always link kernel32.lib and add the rest of the import
+        // libraries below by using an empty extern block. This works because extern blocks are not
+        // connected to the library given in the #[link] attribute.
+        #[link(name = "kernel32")]
+        unsafe extern $abi {
+            $(#[link_name=$link_name])?
+            pub fn $($function)*;
+        }
+    )
+}
+
+#[cfg(feature = "windows_raw_dylib")]
+pub macro link($($tt:tt)*) {
+    $crate::link_raw_dylib!($($tt)*)
+}
+
 #[cfg(not(feature = "windows_raw_dylib"))]
 pub macro link {
     ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
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..f0acb7f7141 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
@@ -350,7 +355,7 @@ impl Step for CodegenBackend {
         cargo
             .arg("--manifest-path")
             .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
-        rustc_cargo_env(builder, &mut cargo, target, build_compiler.stage);
+        rustc_cargo_env(builder, &mut cargo, target);
 
         let _guard = builder.msg_check(format!("rustc_codegen_{backend}"), target, None);
 
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 09bb2e35bda..c7e7b0160b1 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::{
@@ -1316,15 +1316,10 @@ pub fn rustc_cargo(
         cargo.env("RUSTC_WRAPPER", ccache);
     }
 
-    rustc_cargo_env(builder, cargo, target, build_compiler.stage);
+    rustc_cargo_env(builder, cargo, target);
 }
 
-pub fn rustc_cargo_env(
-    builder: &Builder<'_>,
-    cargo: &mut Cargo,
-    target: TargetSelection,
-    build_stage: u32,
-) {
+pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
     cargo
@@ -1379,18 +1374,24 @@ pub fn rustc_cargo_env(
         cargo.rustflag("--cfg=llvm_enzyme");
     }
 
-    // Note that this is disabled if LLVM itself is disabled or we're in a check
-    // build. If we are in a check build we still go ahead here presuming we've
-    // detected that LLVM is already built and good to go which helps prevent
-    // busting caches (e.g. like #71152).
+    // These conditionals represent a tension between three forces:
+    // - For non-check builds, we need to define some LLVM-related environment
+    //   variables, requiring LLVM to have been built.
+    // - For check builds, we want to avoid building LLVM if possible.
+    // - Check builds and non-check builds should have the same environment if
+    //   possible, to avoid unnecessary rebuilds due to cache-busting.
+    //
+    // Therefore we try to avoid building LLVM for check builds, but only if
+    // building LLVM would be expensive. If "building" LLVM is cheap
+    // (i.e. it's already built or is downloadable), we prefer to maintain a
+    // consistent environment between check and non-check builds.
     if builder.config.llvm_enabled(target) {
-        let building_is_expensive =
+        let building_llvm_is_expensive =
             crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)
                 .should_build();
-        // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
-        let can_skip_build = builder.kind == Kind::Check && builder.top_stage == build_stage;
-        let should_skip_build = building_is_expensive && can_skip_build;
-        if !should_skip_build {
+
+        let skip_llvm = (builder.kind == Kind::Check) && building_llvm_is_expensive;
+        if !skip_llvm {
             rustc_llvm_env(builder, cargo, target)
         }
     }
@@ -1407,6 +1408,9 @@ pub fn rustc_cargo_env(
 
 /// Pass down configuration from the LLVM build into the build of
 /// rustc_llvm and rustc_codegen_llvm.
+///
+/// Note that this has the side-effect of _building LLVM_, which is sometimes
+/// unwanted (e.g. for check builds).
 fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
     if builder.config.is_rust_llvm(target) {
         cargo.env("LLVM_RUSTLLVM", "1");
@@ -1665,7 +1669,7 @@ impl Step for CodegenBackend {
         cargo
             .arg("--manifest-path")
             .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
-        rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
+        rustc_cargo_env(builder, &mut cargo, target);
 
         // Ideally, we'd have a separate step for the individual codegen backends,
         // like we have in tests (test::CodegenGCC) but that would require a lot of restructuring.
@@ -2050,19 +2054,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 +2094,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 +2261,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 +2291,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 +2306,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/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index 899e3fd9a45..d4cbbe60921 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -220,21 +220,18 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
     t!(fs::create_dir_all(install_dir));
 
     // GCC creates files (e.g. symlinks to the downloaded dependencies)
-    // in the source directory, which does not work with our CI setup, where we mount
+    // in the source directory, which does not work with our CI/Docker setup, where we mount
     // source directories as read-only on Linux.
-    // Therefore, as a part of the build in CI, we first copy the whole source directory
-    // to the build directory, and perform the build from there.
-    let src_dir = if builder.config.is_running_on_ci {
-        let src_dir = builder.gcc_out(target).join("src");
-        if src_dir.exists() {
-            builder.remove_dir(&src_dir);
-        }
-        builder.create_dir(&src_dir);
-        builder.cp_link_r(root, &src_dir);
-        src_dir
-    } else {
-        root.clone()
-    };
+    // And in general, we shouldn't be modifying the source directories if possible, even for local
+    // builds.
+    // Therefore, we first copy the whole source directory to the build directory, and perform the
+    // build from there.
+    let src_dir = builder.gcc_out(target).join("src");
+    if src_dir.exists() {
+        builder.remove_dir(&src_dir);
+    }
+    builder.create_dir(&src_dir);
+    builder.cp_link_r(root, &src_dir);
 
     command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
     let mut configure_cmd = command(src_dir.join("configure"));
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..7652ea1a488 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1757,6 +1757,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         cmd.arg("--host").arg(&*compiler.host.triple);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
 
+        if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) {
+            cmd.arg("--codegen-backend").arg(&codegen_backend);
+        }
+
         if builder.build.config.llvm_enzyme {
             cmd.arg("--has-enzyme");
         }
@@ -1810,7 +1814,24 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         }
 
         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
-        flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
+        flags.push(format!(
+            "-Cdebuginfo={}",
+            if suite == "codegen" {
+                // codegen tests typically check LLVM IR and are sensitive to additional debuginfo.
+                // So do not apply `rust.debuginfo-level-tests` for codegen tests.
+                if builder.config.rust_debuginfo_level_tests
+                    != crate::core::config::DebuginfoLevel::None
+                {
+                    println!(
+                        "NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
+                        builder.config.rust_debuginfo_level_tests
+                    );
+                }
+                crate::core::config::DebuginfoLevel::None
+            } else {
+                builder.config.rust_debuginfo_level_tests
+            }
+        ));
         flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
 
         if suite != "mir-opt" {
@@ -2945,7 +2966,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);
@@ -3386,7 +3408,7 @@ impl Step for CodegenCranelift {
             cargo
                 .arg("--manifest-path")
                 .arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
-            compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
+            compile::rustc_cargo_env(builder, &mut cargo, target);
 
             // Avoid incremental cache issues when changing rustc
             cargo.env("CARGO_BUILD_INCREMENTAL", "false");
@@ -3518,7 +3540,7 @@ impl Step for CodegenGCC {
             cargo
                 .arg("--manifest-path")
                 .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
-            compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
+            compile::rustc_cargo_env(builder, &mut cargo, target);
             add_cg_gcc_cargo_flags(&mut cargo, &gcc);
 
             // Avoid incremental cache issues when changing rustc
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..e60a115b19d 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -712,7 +712,11 @@ mod snapshot {
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         ");
+    }
 
+    #[test]
+    fn build_rustc_no_explicit_stage() {
+        let ctx = TestCtx::new();
         insta::assert_snapshot!(
             ctx.config("build")
                 .path("rustc")
@@ -769,11 +773,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 +797,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 +1066,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 +1106,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>
         ");
     }
 
@@ -1294,17 +1307,19 @@ mod snapshot {
             ctx.config("check")
                 .path("compiler")
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> cranelift 1 <host>
         [check] rustc 0 <host> -> gcc 1 <host>
         ");
+    }
 
+    #[test]
+    fn check_rustc_no_explicit_stage() {
+        let ctx = TestCtx::new();
         insta::assert_snapshot!(
             ctx.config("check")
                 .path("rustc")
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         ");
     }
@@ -1324,7 +1339,6 @@ mod snapshot {
                 .path("compiler")
                 .stage(1)
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> cranelift 1 <host>
         [check] rustc 0 <host> -> gcc 1 <host>
@@ -1456,7 +1470,6 @@ mod snapshot {
                 .paths(&["library", "compiler"])
                 .args(&args)
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> cranelift 1 <host>
         [check] rustc 0 <host> -> gcc 1 <host>
@@ -1470,7 +1483,6 @@ mod snapshot {
             ctx.config("check")
                 .path("miri")
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> Miri 1 <host>
         ");
@@ -1491,7 +1503,6 @@ mod snapshot {
                 .path("miri")
                 .stage(1)
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> Miri 1 <host>
         ");
@@ -1544,7 +1555,6 @@ mod snapshot {
             ctx.config("check")
                 .path("rustc_codegen_cranelift")
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> cranelift 1 <host>
         [check] rustc 0 <host> -> gcc 1 <host>
@@ -1558,7 +1568,6 @@ mod snapshot {
             ctx.config("check")
                 .path("rust-analyzer")
                 .render_steps(), @r"
-        [build] llvm <host>
         [check] rustc 0 <host> -> rustc 1 <host>
         [check] rustc 0 <host> -> rust-analyzer 1 <host>
         ");
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 28958b60fc3..22a75183404 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -697,7 +697,7 @@ impl Config {
         config.change_id = toml.change_id.inner;
 
         let Build {
-            mut description,
+            description,
             build,
             host,
             target,
@@ -749,7 +749,7 @@ impl Config {
             compiletest_diff_tool,
             compiletest_use_stage0_libtest,
             tidy_extra_checks,
-            mut ccache,
+            ccache,
             exclude,
         } = toml.build.unwrap_or_default();
 
@@ -942,7 +942,7 @@ impl Config {
         config.rust_profile_use = flags_rust_profile_use;
         config.rust_profile_generate = flags_rust_profile_generate;
 
-        config.apply_rust_config(toml.rust, flags_warnings, &mut description);
+        config.apply_rust_config(toml.rust, flags_warnings);
 
         config.reproducible_artifacts = flags_reproducible_artifact;
         config.description = description;
@@ -963,7 +963,7 @@ impl Config {
             config.channel = channel;
         }
 
-        config.apply_llvm_config(toml.llvm, &mut ccache);
+        config.apply_llvm_config(toml.llvm);
 
         config.apply_gcc_config(toml.gcc);
 
diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs
index 4774e202bd8..1f0cecd145c 100644
--- a/src/bootstrap/src/core/config/toml/llvm.rs
+++ b/src/bootstrap/src/core/config/toml/llvm.rs
@@ -17,8 +17,6 @@ define_config! {
         tests: Option<bool> = "tests",
         enzyme: Option<bool> = "enzyme",
         plugins: Option<bool> = "plugins",
-        // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache
-        ccache: Option<StringOrBool> = "ccache",
         static_libstdcpp: Option<bool> = "static-libstdcpp",
         libzstd: Option<bool> = "libzstd",
         ninja: Option<bool> = "ninja",
@@ -97,7 +95,6 @@ pub fn check_incompatible_options_for_ci_llvm(
         assertions: _,
         tests: _,
         plugins,
-        ccache: _,
         static_libstdcpp: _,
         libzstd,
         ninja: _,
@@ -149,11 +146,7 @@ pub fn check_incompatible_options_for_ci_llvm(
 }
 
 impl Config {
-    pub fn apply_llvm_config(
-        &mut self,
-        toml_llvm: Option<Llvm>,
-        ccache: &mut Option<StringOrBool>,
-    ) {
+    pub fn apply_llvm_config(&mut self, toml_llvm: Option<Llvm>) {
         let mut llvm_tests = None;
         let mut llvm_enzyme = None;
         let mut llvm_offload = None;
@@ -168,7 +161,6 @@ impl Config {
                 tests,
                 enzyme,
                 plugins,
-                ccache: llvm_ccache,
                 static_libstdcpp,
                 libzstd,
                 ninja,
@@ -191,13 +183,7 @@ impl Config {
                 download_ci_llvm,
                 build_config,
             } = llvm;
-            if llvm_ccache.is_some() {
-                eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead.");
-            }
 
-            if ccache.is_none() {
-                *ccache = llvm_ccache;
-            }
             set(&mut self.ninja_in_file, ninja);
             llvm_tests = tests;
             llvm_enzyme = enzyme;
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index 0fae235bb93..71fab0e6ae6 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -36,8 +36,6 @@ define_config! {
         incremental: Option<bool> = "incremental",
         default_linker: Option<String> = "default-linker",
         channel: Option<String> = "channel",
-        // FIXME: Remove this field at Q2 2025, it has been replaced by build.description
-        description: Option<String> = "description",
         musl_root: Option<String> = "musl-root",
         rpath: Option<bool> = "rpath",
         strip: Option<bool> = "strip",
@@ -320,7 +318,6 @@ pub fn check_incompatible_options_for_ci_rustc(
         jemalloc,
         rpath,
         channel,
-        description,
         default_linker,
         std_features,
 
@@ -388,7 +385,6 @@ pub fn check_incompatible_options_for_ci_rustc(
     err!(current_rust_config.std_features, std_features, "rust");
 
     warn!(current_rust_config.channel, channel, "rust");
-    warn!(current_rust_config.description, description, "rust");
 
     Ok(())
 }
@@ -415,12 +411,7 @@ pub(crate) fn validate_codegen_backends(backends: Vec<String>, section: &str) ->
 }
 
 impl Config {
-    pub fn apply_rust_config(
-        &mut self,
-        toml_rust: Option<Rust>,
-        warnings: Warnings,
-        description: &mut Option<String>,
-    ) {
+    pub fn apply_rust_config(&mut self, toml_rust: Option<Rust>, warnings: Warnings) {
         let mut debug = None;
         let mut rustc_debug_assertions = None;
         let mut std_debug_assertions = None;
@@ -459,7 +450,6 @@ impl Config {
                 randomize_layout,
                 default_linker,
                 channel: _, // already handled above
-                description: rust_description,
                 musl_root,
                 rpath,
                 verbose_tests,
@@ -541,6 +531,14 @@ impl Config {
             lld_enabled = lld_enabled_toml;
             std_features = std_features_toml;
 
+            if optimize_toml.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) {
+                eprintln!(
+                    "WARNING: setting `optimize` to `false` is known to cause errors and \
+                    should be considered unsupported. Refer to `bootstrap.example.toml` \
+                    for more details."
+                );
+            }
+
             optimize = optimize_toml;
             self.rust_new_symbol_mangling = new_symbol_mangling;
             set(&mut self.rust_optimize_tests, optimize_tests);
@@ -552,14 +550,6 @@ impl Config {
             set(&mut self.jemalloc, jemalloc);
             set(&mut self.test_compare_mode, test_compare_mode);
             set(&mut self.backtrace, backtrace);
-            if rust_description.is_some() {
-                eprintln!(
-                    "Warning: rust.description is deprecated. Use build.description instead."
-                );
-            }
-            if description.is_none() {
-                *description = rust_description;
-            }
             set(&mut self.rust_dist_src, dist_src);
             set(&mut self.verbose_tests, verbose_tests);
             // in the case "false" is set explicitly, do not overwrite the command line args
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/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index d888a7863bc..f802640a42d 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -481,4 +481,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.",
     },
+    ChangeInfo {
+        change_id: 143926,
+        severity: ChangeSeverity::Warning,
+        summary: "Removed `rust.description` and `llvm.ccache` as it was deprecated in #137723 and #136941 long time ago.",
+    },
 ];
diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs
index 05de8fd2d42..266eedc6245 100644
--- a/src/build_helper/src/lib.rs
+++ b/src/build_helper/src/lib.rs
@@ -5,6 +5,7 @@ pub mod drop_bomb;
 pub mod fs;
 pub mod git;
 pub mod metrics;
+pub mod npm;
 pub mod stage0_parser;
 pub mod targets;
 pub mod util;
diff --git a/src/build_helper/src/npm.rs b/src/build_helper/src/npm.rs
new file mode 100644
index 00000000000..dedef40978d
--- /dev/null
+++ b/src/build_helper/src/npm.rs
@@ -0,0 +1,30 @@
+use std::error::Error;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::{fs, io};
+
+/// Install an exact package version, and return the path of `node_modules`.
+pub fn install_one(
+    out_dir: &Path,
+    npm_bin: &Path,
+    pkg_name: &str,
+    pkg_version: &str,
+) -> Result<PathBuf, io::Error> {
+    let nm_path = out_dir.join("node_modules");
+    let _ = fs::create_dir(&nm_path);
+    let mut child = Command::new(npm_bin)
+        .arg("install")
+        .arg("--audit=false")
+        .arg("--fund=false")
+        .arg(format!("{pkg_name}@{pkg_version}"))
+        .current_dir(out_dir)
+        .spawn()?;
+    let exit_status = child.wait()?;
+    if !exit_status.success() {
+        eprintln!("npm install did not exit successfully");
+        return Err(io::Error::other(Box::<dyn Error + Send + Sync>::from(format!(
+            "npm install returned exit code {exit_status}"
+        ))));
+    }
+    Ok(nm_path)
+}
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile
index 2f9d0010573..e73fbe506f7 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile
@@ -50,9 +50,7 @@ ENV RUST_CONFIGURE_ARGS \
 
 COPY scripts/shared.sh /scripts/
 
-ARG SCRIPT_ARG
+COPY scripts/stage_2_test_set1.sh /scripts/
+COPY scripts/stage_2_test_set2.sh /scripts/
 
-COPY scripts/stage_2_test_set1.sh /tmp/
-COPY scripts/stage_2_test_set2.sh /tmp/
-
-ENV SCRIPT "/tmp/${SCRIPT_ARG}"
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 44f6a8d2a15..01f19eac1d2 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -96,12 +96,10 @@ ENV RUST_CONFIGURE_ARGS \
       --set rust.lto=thin \
       --set rust.codegen-units=1
 
-ARG SCRIPT_ARG
-
 COPY host-x86_64/dist-x86_64-linux/dist.sh /scripts/
 COPY host-x86_64/dist-x86_64-linux/dist-alt.sh /scripts/
 
-ENV SCRIPT /scripts/${SCRIPT_ARG}
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
 
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
 
diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 58e66fd637a..be3df9d4036 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -23,7 +23,7 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
-ARG SCRIPT_ARG
 COPY scripts/stage_2_test_set1.sh /scripts/
 COPY scripts/stage_2_test_set2.sh /scripts/
-ENV SCRIPT ${SCRIPT_ARG}
+COPY scripts/i686-gnu-nopt-2.sh /scripts/
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
index a715f7182d2..00cd24b89db 100644
--- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
@@ -24,7 +24,6 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
-ARG SCRIPT_ARG
 COPY scripts/stage_2_test_set1.sh /scripts/
 COPY scripts/stage_2_test_set2.sh /scripts/
-ENV SCRIPT /scripts/${SCRIPT_ARG}
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
index c09be047c6a..5cba7c564f1 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
@@ -57,12 +57,10 @@ ENV RUST_CONFIGURE_ARGS \
 
 COPY scripts/shared.sh /scripts/
 
-ARG SCRIPT_ARG
+COPY scripts/x86_64-gnu-llvm.sh /scripts/
+COPY scripts/x86_64-gnu-llvm2.sh /scripts/
+COPY scripts/x86_64-gnu-llvm3.sh /scripts/
+COPY scripts/stage_2_test_set1.sh /scripts/
+COPY scripts/stage_2_test_set2.sh /scripts/
 
-COPY scripts/x86_64-gnu-llvm.sh /tmp/
-COPY scripts/x86_64-gnu-llvm2.sh /tmp/
-COPY scripts/x86_64-gnu-llvm3.sh /tmp/
-COPY scripts/stage_2_test_set1.sh /tmp/
-COPY scripts/stage_2_test_set2.sh /tmp/
-
-ENV SCRIPT "/tmp/${SCRIPT_ARG}"
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
index 83a3bfb37a5..92c2631000f 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
@@ -57,12 +57,10 @@ ENV RUST_CONFIGURE_ARGS \
 
 COPY scripts/shared.sh /scripts/
 
-ARG SCRIPT_ARG
+COPY scripts/x86_64-gnu-llvm.sh /scripts/
+COPY scripts/x86_64-gnu-llvm2.sh /scripts/
+COPY scripts/x86_64-gnu-llvm3.sh /scripts/
+COPY scripts/stage_2_test_set1.sh /scripts/
+COPY scripts/stage_2_test_set2.sh /scripts/
 
-COPY scripts/x86_64-gnu-llvm.sh /tmp/
-COPY scripts/x86_64-gnu-llvm2.sh /tmp/
-COPY scripts/x86_64-gnu-llvm3.sh /tmp/
-COPY scripts/stage_2_test_set1.sh /tmp/
-COPY scripts/stage_2_test_set2.sh /tmp/
-
-ENV SCRIPT "/tmp/${SCRIPT_ARG}"
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile
index b937bc3e678..ad2ee85c7bb 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile
@@ -46,12 +46,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
 
 COPY scripts/shared.sh /scripts/
 
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-#
-# We also specify the version in case we need to update it to go around cache limitations.
-#
-# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case
-# the local version of the package is different than the one used by the CI.
 ENV SCRIPT /tmp/check-miri.sh ../x.py
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index e770c58bd9c..95357d22937 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -76,8 +76,6 @@ COPY scripts/nodejs.sh /scripts/
 RUN sh /scripts/nodejs.sh /node
 ENV PATH="/node/bin:${PATH}"
 
-COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
-
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json \
@@ -91,15 +89,6 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
 
 COPY scripts/shared.sh /scripts/
 
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-#
-# We also specify the version in case we need to update it to go around cache limitations.
-#
-# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case
-# the local version of the package is different than the one used by the CI.
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
-  npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \
   python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
   python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
deleted file mode 100644
index b9f8e558df4..00000000000
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ /dev/null
@@ -1 +0,0 @@
-0.21.1
\ No newline at end of file
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index da7d084d48d..044f5a8fff3 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -114,14 +114,6 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
         "$context"
     )
 
-    # If the environment variable DOCKER_SCRIPT is defined,
-    # set the build argument SCRIPT_ARG to DOCKER_SCRIPT.
-    # In this way, we run the script defined in CI,
-    # instead of the one defined in the Dockerfile.
-    if [ -n "${DOCKER_SCRIPT+x}" ]; then
-      build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}")
-    fi
-
     GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1"
     # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci
     # ghcr.io registry. If it is not possible, we fall back to building the image
@@ -341,6 +333,10 @@ if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then
   echo "Setting extra environment values for docker: $extra_env"
 fi
 
+if [ -n "${DOCKER_SCRIPT}" ]; then
+  extra_env="$extra_env --env SCRIPT=\"/scripts/${DOCKER_SCRIPT}\""
+fi
+
 docker \
   run \
   --workdir /checkout/obj \
diff --git a/src/ci/docker/scripts/i686-gnu-nopt-2.sh b/src/ci/docker/scripts/i686-gnu-nopt-2.sh
new file mode 100755
index 00000000000..4c171739daf
--- /dev/null
+++ b/src/ci/docker/scripts/i686-gnu-nopt-2.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -ex
+
+python3 ../x.py test --stage 1 --set rust.optimize=false library/std &&
+/scripts/stage_2_test_set2.sh
diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm2.sh b/src/ci/docker/scripts/x86_64-gnu-llvm2.sh
index fe5382aaa48..0060b9bfd23 100755
--- a/src/ci/docker/scripts/x86_64-gnu-llvm2.sh
+++ b/src/ci/docker/scripts/x86_64-gnu-llvm2.sh
@@ -4,7 +4,7 @@ set -ex
 
 ##### Test stage 2 #####
 
-/tmp/stage_2_test_set1.sh
+/scripts/stage_2_test_set1.sh
 
 # Run the `mir-opt` tests again but this time for a 32-bit target.
 # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 445fc0dd018..0a6ebe44b3d 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -34,6 +34,8 @@ runners:
     os: windows-2022
     <<: *base-job
 
+  # NOTE: windows-2025 has less disk space available than windows-2022,
+  # because the D drive is missing.
   - &job-windows-25
     os: windows-2025
     <<: *base-job
@@ -170,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
@@ -315,16 +317,14 @@ auto:
   - name: i686-gnu-nopt-1
     env:
       IMAGE: i686-gnu-nopt
-      DOCKER_SCRIPT: /scripts/stage_2_test_set1.sh
+      DOCKER_SCRIPT: stage_2_test_set1.sh
     <<: *job-linux-4c
 
   # Skip tests that run in i686-gnu-nopt-1
   - name: i686-gnu-nopt-2
     env:
       IMAGE: i686-gnu-nopt
-      DOCKER_SCRIPT: >-
-        python3 ../x.py test --stage 1 --set rust.optimize=false library/std &&
-        /scripts/stage_2_test_set2.sh
+      DOCKER_SCRIPT: i686-gnu-nopt-2.sh
     <<: *job-linux-4c
 
   - name: pr-check-1
@@ -544,13 +544,13 @@ auto:
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler
       SCRIPT: make ci-msvc-py
-    <<: *job-windows-25
+    <<: *job-windows
 
   - name: x86_64-msvc-2
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler
       SCRIPT: make ci-msvc-ps1
-    <<: *job-windows-25
+    <<: *job-windows
 
   # i686-msvc is split into two jobs to run tests in parallel.
   - name: i686-msvc-1
diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh
index ad852071f29..ed87628659b 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -43,4 +43,9 @@ if isWindows && isKnownToBeMingwBuild; then
     curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
     7z x -y mingw.7z > /dev/null
     ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")"
+
+    # Initialize mingw for the user.
+    # This should be done by github but isn't for some reason.
+    # (see https://github.com/actions/runner-images/issues/12600)
+    /c/msys64/usr/bin/bash -lc ' '
 fi
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 3f10132b684..f6b7efe51a1 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-fd2eb391d032181459773f3498c17b198513e0d0
+460259d14de0274b97b8801e08cb2fe5f16fdac5
diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md
index c7aa2714668..87b0103a7bc 100644
--- a/src/doc/rustc-dev-guide/src/effects.md
+++ b/src/doc/rustc-dev-guide/src/effects.md
@@ -67,10 +67,8 @@ in [`wfcheck::check_impl`].
 Here's an example:
 
 ```rust
-#[const_trait]
-trait Bar {}
-#[const_trait]
-trait Foo: ~const Bar {}
+const trait Bar {}
+const trait Foo: ~const Bar {}
 // `const_conditions` contains `HostEffect(Self: Bar, maybe)`
 
 impl const Bar for () {}
@@ -85,8 +83,7 @@ predicates of the trait method, and we attempt to prove the predicates of the
 impl method. We do the same for `const_conditions`:
 
 ```rust
-#[const_trait]
-trait Foo {
+const trait Foo {
     fn hi<T: ~const Default>();
 }
 
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 63aa08c389c..5c3ae359ba0 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`       |
@@ -203,6 +205,8 @@ settings:
   on `wasm32-unknown-unknown` target because the target does not support the
   `proc-macro` crate type.
 - `needs-target-std` — ignores if target platform does not have std support.
+- `ignore-backends` — ignores the listed backends, separated by whitespace characters.
+- `needs-backends` — only runs the test if current codegen backend is listed.
 
 The following directives will check LLVM support:
 
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/mod.rs b/src/librustdoc/clean/mod.rs
index e7a1f4d8397..1265a39d27b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -390,7 +390,8 @@ pub(crate) fn clean_predicate<'tcx>(
         ty::ClauseKind::ConstEvaluatable(..)
         | ty::ClauseKind::WellFormed(..)
         | ty::ClauseKind::ConstArgHasType(..)
-        // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `[const]`.
+        | ty::ClauseKind::UnstableFeature(..)
+        // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`.
         | ty::ClauseKind::HostEffect(_) => None,
     }
 }
@@ -2864,7 +2865,7 @@ fn clean_maybe_renamed_item<'tcx>(
             ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
             }
-            ItemKind::Trait(_, _, _, generics, bounds, item_ids) => {
+            ItemKind::Trait(_, _, _, _, generics, bounds, item_ids) => {
                 let items = item_ids
                     .iter()
                     .map(|&ti| clean_trait_item(cx.tcx.hir_trait_item(ti), cx))
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 20babc6168b..5ac5da24299 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -648,7 +648,7 @@ impl Item {
             let sig = tcx.fn_sig(def_id).skip_binder();
             let constness = if tcx.is_const_fn(def_id) {
                 // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent
-                // or that have a `#[const_trait]` parent. Do not display those as `const` in rustdoc because we
+                // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we
                 // won't be printing correct syntax plus the syntax is unstable.
                 match tcx.opt_associated_item(def_id) {
                     Some(ty::AssocItem {
@@ -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 bf3f7607274..813fdee57e1 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -3,6 +3,7 @@ use std::fmt::{self, Display, Write as _};
 use std::sync::LazyLock as Lazy;
 use std::{ascii, mem};
 
+use rustc_ast::join_path_idents;
 use rustc_ast::tokenstream::TokenTree;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -24,7 +25,7 @@ use crate::clean::{
     clean_middle_ty, inline,
 };
 use crate::core::DocContext;
-use crate::display::{Joined as _, MaybeDisplay as _};
+use crate::display::Joined as _;
 
 #[cfg(test)]
 mod tests;
@@ -251,13 +252,7 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String {
         hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
     };
 
-    fmt::from_fn(|f| {
-        segments
-            .iter()
-            .map(|seg| (seg.ident.name != kw::PathRoot).then_some(seg.ident).maybe_display())
-            .joined("::", f)
-    })
-    .to_string()
+    join_path_idents(segments.iter().map(|seg| seg.ident))
 }
 
 pub(crate) fn build_deref_target_impls(
@@ -348,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/cache.rs b/src/librustdoc/formats/cache.rs
index 4989bd718c9..5191120ebdb 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,5 +1,6 @@
 use std::mem;
 
+use rustc_ast::join_path_syms;
 use rustc_attr_data_structures::StabilityLevel;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
@@ -13,7 +14,6 @@ use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
-use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::IndexItem;
 use crate::html::render::search_index::get_function_type_for_search;
@@ -558,7 +558,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
         clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id),
         _ => item_def_id,
     };
-    let path = join_with_double_colon(parent_path);
+    let path = join_path_syms(parent_path);
     let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
         item_id.as_def_id()
     } else {
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 bcb3e57c844..be8a2d511e9 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -14,6 +14,7 @@ use std::slice;
 
 use itertools::{Either, Itertools};
 use rustc_abi::ExternAbi;
+use rustc_ast::join_path_syms;
 use rustc_attr_data_structures::{ConstStability, StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
@@ -25,7 +26,7 @@ use rustc_span::symbol::kw;
 use rustc_span::{Symbol, sym};
 use tracing::{debug, trace};
 
-use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length};
+use super::url_parts_builder::UrlPartsBuilder;
 use crate::clean::types::ExternalLocation;
 use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
@@ -113,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;")
             }
         })
     }
@@ -369,18 +370,6 @@ pub(crate) enum HrefError {
     NotInExternalCache,
 }
 
-// Panics if `syms` is empty.
-pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String {
-    let mut s = String::with_capacity(estimate_item_path_byte_length(syms.len()));
-    // NOTE: using `Joined::joined` here causes a noticeable perf regression
-    s.push_str(syms[0].as_str());
-    for sym in &syms[1..] {
-        s.push_str("::");
-        s.push_str(sym.as_str());
-    }
-    s
-}
-
 /// This function is to get the external macro path because they are not in the cache used in
 /// `href_with_root_path`.
 fn generate_macro_def_id_path(
@@ -605,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()))
 }
 
@@ -672,7 +661,7 @@ pub(crate) fn link_tooltip(
             write!(f, "{}", cx.tcx().item_name(id))?;
         } else if !fqp.is_empty() {
             write!(f, "{shortty} ")?;
-            fqp.iter().joined("::", f)?;
+            write!(f, "{}", join_path_syms(fqp))?;
         }
         Ok(())
     })
@@ -703,7 +692,7 @@ fn resolved_path(
                     write!(
                         f,
                         "{path}::{anchor}",
-                        path = join_with_double_colon(&fqp[..fqp.len() - 1]),
+                        path = join_path_syms(&fqp[..fqp.len() - 1]),
                         anchor = print_anchor(did, *fqp.last().unwrap(), cx)
                     )
                 } else {
@@ -835,7 +824,7 @@ pub(crate) fn print_anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl D
             write!(
                 f,
                 r#"<a class="{short_ty}" href="{url}" title="{short_ty} {path}">{text}</a>"#,
-                path = join_with_double_colon(&fqp),
+                path = join_path_syms(fqp),
                 text = EscapeBodyText(text.as_str()),
             )
         } else {
@@ -1095,7 +1084,7 @@ impl clean::QPathData {
                                     title=\"type {path}::{name}\">{name}</a>",
                         shortty = ItemType::AssocType,
                         name = assoc.name,
-                        path = join_with_double_colon(&path),
+                        path = join_path_syms(path),
                     )
                 } else {
                     write!(f, "{}", assoc.name)
@@ -1126,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 {
@@ -1230,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)
                 })
@@ -1352,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 3b4dae841ee..5ceb1fc988d 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -6,6 +6,7 @@ use std::path::{Path, PathBuf};
 use std::sync::mpsc::{Receiver, channel};
 
 use askama::Template;
+use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
@@ -27,7 +28,6 @@ use crate::formats::FormatRenderer;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
-use crate::html::format::join_with_double_colon;
 use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
 use crate::html::render::write_shared::write_shared;
 use crate::html::url_parts_builder::UrlPartsBuilder;
@@ -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 {
@@ -211,7 +209,7 @@ impl<'tcx> Context<'tcx> {
                 title.push_str(" in ");
             }
             // No need to include the namespace for primitive types and keywords
-            title.push_str(&join_with_double_colon(&self.current));
+            title.push_str(&join_path_syms(&self.current));
         };
         title.push_str(" - Rust");
         let tyname = it.type_();
@@ -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 06de4944d97..872dbbcd19e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -49,6 +49,7 @@ use std::{fs, str};
 
 use askama::Template;
 use itertools::Either;
+use rustc_ast::join_path_syms;
 use rustc_attr_data_structures::{
     ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
 };
@@ -74,9 +75,9 @@ use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::format::{
-    Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
-    print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause,
-    visibility_print_with_space, write_str,
+    Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space,
+    print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
+    write_str,
 };
 use crate::html::markdown::{
     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
@@ -1109,7 +1110,7 @@ fn since_to_string(since: &StableSince) -> Option<String> {
     match since {
         StableSince::Version(since) => Some(since.to_string()),
         StableSince::Current => Some(RustcVersion::CURRENT.to_string()),
-        StableSince::Err => None,
+        StableSince::Err(_) => None,
     }
 }
 
@@ -1482,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);
     }
 }
 
@@ -2057,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());
@@ -2555,7 +2555,7 @@ fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec<String>
         let fqp = cache.exact_paths.get(&did).or_else(get_extern);
 
         if let Some(path) = fqp {
-            out.push(join_with_double_colon(path));
+            out.push(join_path_syms(path));
         }
     };
 
@@ -2569,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 667d39e9bc2..02ee34aaac6 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -4,6 +4,7 @@ use std::iter;
 
 use askama::Template;
 use rustc_abi::VariantIdx;
+use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
@@ -30,8 +31,8 @@ use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
 use crate::html::format::{
-    Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
-    print_constness_with_space, print_where_clause, visibility_print_with_space,
+    Ending, PrintWithSpace, print_abi_with_space, print_constness_with_space, print_where_clause,
+    visibility_print_with_space,
 };
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
@@ -1424,7 +1425,7 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) ->
                 iter::repeat_n("..", cx.current.len()).chain(iter::once("type.impl")).collect();
             js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
             js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
-            let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f));
+            let self_path = join_path_syms(self_fqp);
             write!(
                 w,
                 "<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>",
@@ -1450,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 {
@@ -1981,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>(())
@@ -2070,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(())
@@ -2256,7 +2253,7 @@ pub(crate) fn compare_names(left: &str, right: &str) -> Ordering {
 }
 
 pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
-    let mut s = join_with_double_colon(&cx.current);
+    let mut s = join_path_syms(&cx.current);
     s.push_str("::");
     s.push_str(item.name.unwrap().as_str());
     s
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index aff8684ee3a..3c9be29ccc3 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -4,6 +4,7 @@ use std::collections::hash_map::Entry;
 use std::collections::{BTreeMap, VecDeque};
 
 use encode::{bitmap_to_string, write_vlqhex_to_string};
+use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
@@ -17,7 +18,6 @@ use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
 use crate::clean::{self, utils};
 use crate::formats::cache::{Cache, OrphanImplItem};
 use crate::formats::item_type::ItemType;
-use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::ordered_json::OrderedJson;
 use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
@@ -78,7 +78,7 @@ pub(crate) fn build_index(
                 ty: item.type_(),
                 defid: item.item_id.as_def_id(),
                 name: item.name.unwrap(),
-                path: join_with_double_colon(&fqp[..fqp.len() - 1]),
+                path: join_path_syms(&fqp[..fqp.len() - 1]),
                 desc,
                 parent: Some(parent),
                 parent_idx: None,
@@ -116,7 +116,7 @@ pub(crate) fn build_index(
     // Set up alias indexes.
     for (i, item) in cache.search_index.iter().enumerate() {
         for alias in &item.aliases[..] {
-            aliases.entry(alias.as_str().to_lowercase()).or_default().push(i);
+            aliases.entry(alias.to_string()).or_default().push(i);
         }
     }
 
@@ -416,7 +416,7 @@ pub(crate) fn build_index(
                             if fqp.len() < 2 {
                                 return None;
                             }
-                            join_with_double_colon(&fqp[..fqp.len() - 1])
+                            join_path_syms(&fqp[..fqp.len() - 1])
                         };
                     if path == item.path {
                         return None;
@@ -427,10 +427,10 @@ pub(crate) fn build_index(
                 let i = <isize as TryInto<usize>>::try_into(parent_idx).unwrap();
                 item.path = {
                     let p = &crate_paths[i].1;
-                    join_with_double_colon(&p[..p.len() - 1])
+                    join_path_syms(&p[..p.len() - 1])
                 };
                 item.exact_path =
-                    crate_paths[i].2.as_ref().map(|xp| join_with_double_colon(&xp[..xp.len() - 1]));
+                    crate_paths[i].2.as_ref().map(|xp| join_path_syms(&xp[..xp.len() - 1]));
             }
 
             // Omit the parent path if it is same to that of the prior item.
@@ -549,11 +549,11 @@ pub(crate) fn build_index(
                     });
                     continue;
                 }
-                let full_path = join_with_double_colon(&path[..path.len() - 1]);
+                let full_path = join_path_syms(&path[..path.len() - 1]);
                 let full_exact_path = exact
                     .as_ref()
                     .filter(|exact| exact.last() == path.last() && exact.len() >= 2)
-                    .map(|exact| join_with_double_colon(&exact[..exact.len() - 1]));
+                    .map(|exact| join_path_syms(&exact[..exact.len() - 1]));
                 let exact_path = extra_paths.len() + self.items.len();
                 let exact_path = full_exact_path.as_ref().map(|full_exact_path| match extra_paths
                     .entry(full_exact_path.clone())
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/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 0078671fcc5..1f691392b17 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -26,6 +26,7 @@ use std::{fmt, fs};
 
 use indexmap::IndexMap;
 use regex::Regex;
+use rustc_ast::join_path_syms;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_middle::ty::TyCtxt;
@@ -43,7 +44,6 @@ use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
-use crate::html::format::join_with_double_colon;
 use crate::html::layout;
 use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
 use crate::html::render::search_index::{SerializedSearchIndex, build_index};
@@ -608,7 +608,7 @@ impl TypeAliasPart {
                     for &(type_alias_fqp, type_alias_item) in type_aliases {
                         cx.id_map.borrow_mut().clear();
                         cx.deref_id_map.borrow_mut().clear();
-                        let type_alias_fqp = join_with_double_colon(&type_alias_fqp);
+                        let type_alias_fqp = join_path_syms(type_alias_fqp);
                         if let Some(ret) = &mut ret {
                             ret.aliases.push(type_alias_fqp);
                         } else {
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index ca2512e5ab6..a9589764547 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -219,6 +219,8 @@ declare namespace rustdoc {
         crate: string,
         descShard: SearchDescShard,
         id: number,
+        // This is the name of the item. For doc aliases, if you want the name of the aliased
+        // item, take a look at `Row.original.name`.
         name: string,
         normalizedName: string,
         word: string,
@@ -227,6 +229,11 @@ declare namespace rustdoc {
         path: string,
         ty: number,
         type: FunctionSearchType | null,
+        descIndex: number,
+        bitIndex: number,
+        implDisambiguator: String | null,
+        is_alias?: boolean,
+        original?: Row,
     }
 
     /**
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 15cad31f555..2caf214ff73 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -830,7 +830,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
  */
 function makePrimitiveElement(name, extra) {
     return Object.assign({
-        name: name,
+        name,
         id: null,
         fullPath: [name],
         pathWithoutLast: [],
@@ -1483,6 +1483,7 @@ class DocSearch {
          */
         this.assocTypeIdNameMap = new Map();
         this.ALIASES = new Map();
+        this.FOUND_ALIASES = new Set();
         this.rootPath = rootPath;
         this.searchState = searchState;
 
@@ -2030,6 +2031,8 @@ class DocSearch {
         // normalized names, type signature objects and fingerprints, and aliases.
         id = 0;
 
+        /** @type {Array<[string, { [key: string]: Array<number> },  number]>} */
+        const allAliases = [];
         for (const [crate, crateCorpus] of rawSearchIndex) {
             // a string representing the lengths of each description shard
             // a string representing the list of function types
@@ -2178,10 +2181,10 @@ class DocSearch {
                 paths[i] = { ty, name, path, exactPath, unboxFlag };
             }
 
-            // convert `item*` into an object form, and construct word indices.
+            // Convert `item*` into an object form, and construct word indices.
             //
-            // before any analysis is performed lets gather the search terms to
-            // search against apart from the rest of the data.  This is a quick
+            // Before any analysis is performed, let's gather the search terms to
+            // search against apart from the rest of the data. This is a quick
             // operation that is cached for the life of the page state so that
             // all other search operations have access to this cached data for
             // faster analysis operations
@@ -2269,29 +2272,58 @@ class DocSearch {
             }
 
             if (aliases) {
-                const currentCrateAliases = new Map();
-                this.ALIASES.set(crate, currentCrateAliases);
-                for (const alias_name in aliases) {
-                    if (!Object.prototype.hasOwnProperty.call(aliases, alias_name)) {
-                        continue;
-                    }
-
-                    /** @type{number[]} */
-                    let currentNameAliases;
-                    if (currentCrateAliases.has(alias_name)) {
-                        currentNameAliases = currentCrateAliases.get(alias_name);
-                    } else {
-                        currentNameAliases = [];
-                        currentCrateAliases.set(alias_name, currentNameAliases);
-                    }
-                    for (const local_alias of aliases[alias_name]) {
-                        currentNameAliases.push(local_alias + currentIndex);
-                    }
-                }
+                // We need to add the aliases in `searchIndex` after we finished filling it
+                // to not mess up indexes.
+                allAliases.push([crate, aliases, currentIndex]);
             }
             currentIndex += itemTypes.length;
             this.searchState.descShards.set(crate, descShardList);
         }
+
+        for (const [crate, aliases, index] of allAliases) {
+            for (const [alias_name, alias_refs] of Object.entries(aliases)) {
+                if (!this.ALIASES.has(crate)) {
+                    this.ALIASES.set(crate, new Map());
+                }
+                const word = alias_name.toLowerCase();
+                const crate_alias_map = this.ALIASES.get(crate);
+                if (!crate_alias_map.has(word)) {
+                    crate_alias_map.set(word, []);
+                }
+                const aliases_map = crate_alias_map.get(word);
+
+                const normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
+                for (const alias of alias_refs) {
+                    const originalIndex = alias + index;
+                    const original = searchIndex[originalIndex];
+                    /** @type {rustdoc.Row} */
+                    const row = {
+                        crate,
+                        name: alias_name,
+                        normalizedName,
+                        is_alias: true,
+                        ty: original.ty,
+                        type: original.type,
+                        paramNames: [],
+                        word,
+                        id,
+                        parent: undefined,
+                        original,
+                        path: "",
+                        implDisambiguator: original.implDisambiguator,
+                        // Needed to load the description of the original item.
+                        // @ts-ignore
+                        descShard: original.descShard,
+                        descIndex: original.descIndex,
+                        bitIndex: original.bitIndex,
+                    };
+                    aliases_map.push(row);
+                    this.nameTrie.insert(normalizedName, id, this.tailTable);
+                    id += 1;
+                    searchIndex.push(row);
+                }
+            }
+        }
         // Drop the (rather large) hash table used for reusing function items
         this.TYPES_POOL = new Map();
         return searchIndex;
@@ -2536,6 +2568,8 @@ class DocSearch {
             parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
             parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
         const maxEditDistance = Math.floor(queryLen / 3);
+        // We reinitialize the `FOUND_ALIASES` map.
+        this.FOUND_ALIASES.clear();
 
         /**
          * @type {Map<string, number>}
@@ -2695,6 +2729,10 @@ class DocSearch {
         const buildHrefAndPath = item => {
             let displayPath;
             let href;
+            if (item.is_alias) {
+                this.FOUND_ALIASES.add(item.word);
+                item = item.original;
+            }
             const type = itemTypes[item.ty];
             const name = item.name;
             let path = item.path;
@@ -3198,8 +3236,7 @@ class DocSearch {
                 result.item = this.searchIndex[result.id];
                 result.word = this.searchIndex[result.id].word;
                 if (isReturnTypeQuery) {
-                    // we are doing a return-type based search,
-                    // deprioritize "clone-like" results,
+                    // We are doing a return-type based search, deprioritize "clone-like" results,
                     // ie. functions that also take the queried type as an argument.
                     const resultItemType = result.item && result.item.type;
                     if (!resultItemType) {
@@ -4259,28 +4296,13 @@ class DocSearch {
             return false;
         }
 
-        // this does not yet have a type in `rustdoc.d.ts`.
-        // @ts-expect-error
-        function createAliasFromItem(item) {
-            return {
-                crate: item.crate,
-                name: item.name,
-                path: item.path,
-                descShard: item.descShard,
-                descIndex: item.descIndex,
-                exactPath: item.exactPath,
-                ty: item.ty,
-                parent: item.parent,
-                type: item.type,
-                is_alias: true,
-                bitIndex: item.bitIndex,
-                implDisambiguator: item.implDisambiguator,
-            };
-        }
-
         // @ts-expect-error
         const handleAliases = async(ret, query, filterCrates, currentCrate) => {
             const lowerQuery = query.toLowerCase();
+            if (this.FOUND_ALIASES.has(lowerQuery)) {
+                return;
+            }
+            this.FOUND_ALIASES.add(lowerQuery);
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
             // @ts-expect-error
@@ -4292,7 +4314,7 @@ class DocSearch {
                     && this.ALIASES.get(filterCrates).has(lowerQuery)) {
                     const query_aliases = this.ALIASES.get(filterCrates).get(lowerQuery);
                     for (const alias of query_aliases) {
-                        aliases.push(createAliasFromItem(this.searchIndex[alias]));
+                        aliases.push(alias);
                     }
                 }
             } else {
@@ -4302,7 +4324,7 @@ class DocSearch {
                         const pushTo = crate === currentCrate ? crateAliases : aliases;
                         const query_aliases = crateAliasesIndex.get(lowerQuery);
                         for (const alias of query_aliases) {
-                            pushTo.push(createAliasFromItem(this.searchIndex[alias]));
+                            pushTo.push(alias);
                         }
                     }
                 }
@@ -4310,9 +4332,9 @@ class DocSearch {
 
             // @ts-expect-error
             const sortFunc = (aaa, bbb) => {
-                if (aaa.path < bbb.path) {
+                if (aaa.original.path < bbb.original.path) {
                     return 1;
-                } else if (aaa.path === bbb.path) {
+                } else if (aaa.original.path === bbb.original.path) {
                     return 0;
                 }
                 return -1;
@@ -4322,20 +4344,9 @@ class DocSearch {
             aliases.sort(sortFunc);
 
             // @ts-expect-error
-            const fetchDesc = alias => {
-                // @ts-expect-error
-                return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ?
-                    "" : this.searchState.loadDesc(alias);
-            };
-            const [crateDescs, descs] = await Promise.all([
-                // @ts-expect-error
-                Promise.all(crateAliases.map(fetchDesc)),
-                Promise.all(aliases.map(fetchDesc)),
-            ]);
-
-            // @ts-expect-error
             const pushFunc = alias => {
-                alias.alias = query;
+                // Cloning `alias` to prevent its fields to be updated.
+                alias = {...alias};
                 const res = buildHrefAndPath(alias);
                 alias.displayPath = pathSplitter(res[0]);
                 alias.fullPath = alias.displayPath + alias.name;
@@ -4347,16 +4358,8 @@ class DocSearch {
                 }
             };
 
-            aliases.forEach((alias, i) => {
-                // @ts-expect-error
-                alias.desc = descs[i];
-            });
             aliases.forEach(pushFunc);
             // @ts-expect-error
-            crateAliases.forEach((alias, i) => {
-                alias.desc = crateDescs[i];
-            });
-            // @ts-expect-error
             crateAliases.forEach(pushFunc);
         };
 
@@ -4802,7 +4805,7 @@ async function addTab(array, query, display) {
         output.className = "search-results " + extraClass;
 
         const lis = Promise.all(array.map(async item => {
-            const name = item.name;
+            const name = item.is_alias ? item.original.name : item.name;
             const type = itemTypes[item.ty];
             const longType = longItemTypes[item.ty];
             const typeName = longType.length !== 0 ? `${longType}` : "?";
@@ -4822,7 +4825,7 @@ async function addTab(array, query, display) {
             let alias = " ";
             if (item.is_alias) {
                 alias = ` <div class="alias">\
-<b>${item.alias}</b><i class="grey">&nbsp;- see&nbsp;</i>\
+<b>${item.name}</b><i class="grey">&nbsp;- see&nbsp;</i>\
 </div>`;
             }
             resultName.insertAdjacentHTML(
@@ -5201,6 +5204,7 @@ function registerSearchEvents() {
         if (searchState.input.value.length === 0) {
             searchState.hideResults();
         } else {
+            // @ts-ignore
             searchState.timeout = setTimeout(search, 500);
         }
     };
@@ -5842,8 +5846,8 @@ Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new In
 // be called ONLY when the whole file has been parsed and loaded.
 
 // @ts-expect-error
-function initSearch(searchIndx) {
-    rawSearchIndex = searchIndx;
+function initSearch(searchIndex) {
+    rawSearchIndex = searchIndex;
     if (typeof window !== "undefined") {
         // @ts-expect-error
         docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
diff --git a/src/librustdoc/html/url_parts_builder.rs b/src/librustdoc/html/url_parts_builder.rs
index 9a533827441..705fa498e8d 100644
--- a/src/librustdoc/html/url_parts_builder.rs
+++ b/src/librustdoc/html/url_parts_builder.rs
@@ -117,7 +117,7 @@ impl UrlPartsBuilder {
 
 /// This is just a guess at the average length of a URL part,
 /// used for [`String::with_capacity`] calls in the [`FromIterator`]
-/// and [`Extend`] impls, and for [estimating item path lengths].
+/// and [`Extend`] impls.
 ///
 /// The value `8` was chosen for two main reasons:
 ///
@@ -125,18 +125,8 @@ impl UrlPartsBuilder {
 /// * jemalloc's size classes are all multiples of eight,
 ///   which means that the amount of memory it allocates will often match
 ///   the amount requested, avoiding wasted bytes.
-///
-/// [estimating item path lengths]: estimate_item_path_byte_length
 const AVG_PART_LENGTH: usize = 8;
 
-/// Estimate the number of bytes in an item's path, based on how many segments it has.
-///
-/// **Note:** This is only to be used with, e.g., [`String::with_capacity()`];
-/// the return value is just a rough estimate.
-pub(crate) const fn estimate_item_path_byte_length(segment_count: usize) -> usize {
-    AVG_PART_LENGTH * segment_count
-}
-
 impl<'a> FromIterator<&'a str> for UrlPartsBuilder {
     fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
         let iter = iter.into_iter();
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/llvm-project b/src/llvm-project
-Subproject d3c793b025645a4565ac59aceb30d2d116ff1a4
+Subproject e8a2ffcf322f45b8dce82c65ab27a3e2430a6b5
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 07df893ae3c..a9d3015ce5c 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
                     cur_f = Some(field);
                 }
             },
-            ItemKind::Trait(is_auto, _safety, _ident, _generics, _generic_bounds, item_ref)
+            ItemKind::Trait(_constness, is_auto, _safety, _ident, _generics, _generic_bounds, item_ref)
                 if self.enable_ordering_for_trait && *is_auto == IsAuto::No =>
             {
                 let mut cur_t: Option<(TraitItemId, Ident)> = None;
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 2bf52216b83..22b781b8929 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -740,7 +740,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                             );
                         }
                     },
-                    ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
+                    ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety, unsafety) {
                         (false, Safety::Unsafe) => span_lint(
                             cx,
                             MISSING_SAFETY_DOC,
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index d32017a8b41..1bf03480c82 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -125,7 +125,7 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP
 
 impl<'tcx> LateLintPass<'tcx> for LenZero {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Trait(_, _, ident, _, _, trait_items) = item.kind
+        if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind
             && !item.span.from_expansion()
         {
             check_trait_items(cx, item, ident, trait_items);
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 045363058d1..d664eaaac70 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -4,6 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{is_path_diagnostic_item, sugg};
+use rustc_ast::join_path_idents;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{self as hir, Expr, ExprKind, GenericArg, QPath, TyKind};
@@ -47,7 +48,7 @@ fn build_full_type(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, app: &mut Applica
         && let QPath::Resolved(None, ty_path) = &ty_qpath
         && let Res::Def(_, ty_did) = ty_path.res
     {
-        let mut ty_str = itertools::join(ty_path.segments.iter().map(|s| s.ident), "::");
+        let mut ty_str = join_path_idents(ty_path.segments.iter().map(|seg| seg.ident));
         let mut first = true;
         let mut append = |arg: &str| {
             write!(&mut ty_str, "{}{arg}", [", ", "<"][usize::from(first)]).unwrap();
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 329f7193437..c4a3d10299b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                 let attrs = cx.tcx.hir_attrs(it.hir_id());
                 check_missing_inline_attrs(cx, attrs, it.span, desc);
             },
-            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => {
+            hir::ItemKind::Trait(ref _constness, ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => {
                 // note: we need to check if the trait is exported so we can't use
                 // `LateLintPass::check_trait_item` here.
                 for &tit in trait_items {
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index cf70e883bd0..216f168471e 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -249,7 +249,7 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool {
             let stable = match since {
                 StableSince::Version(v) => msrv.meets(cx, v),
                 StableSince::Current => msrv.current(cx).is_none(),
-                StableSince::Err => false,
+                StableSince::Err(_) => false,
             };
 
             if !stable {
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 45e54302e32..9182a55081f 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
         // special handling for self trait bounds as these are not considered generics
         // ie. trait Foo: Display {}
         if let Item {
-            kind: ItemKind::Trait(_, _, _, _, bounds, ..),
+            kind: ItemKind::Trait(_, _, _, _, _, bounds, ..),
             ..
         } = item
         {
@@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                     ..
                 }) = segments.first()
                 && let Some(Node::Item(Item {
-                    kind: ItemKind::Trait(_, _, _, _, self_bounds, _),
+                    kind: ItemKind::Trait(_, _, _, _, _, self_bounds, _),
                     ..
                 })) = cx.tcx.hir_get_if_local(*def_id)
             {
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 02281b9e922..944cd91a7fd 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -131,7 +131,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
             return;
         }
         match it.kind {
-            ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, ident, ..) => {
+            ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) => {
                 check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive);
             },
             ItemKind::Enum(ident, _, ref enumdef) => {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index 42254ec8e92..96f0273c439 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -444,6 +444,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
         },
         (
             Trait(box ast::Trait {
+                constness: lc,
                 is_auto: la,
                 safety: lu,
                 ident: li,
@@ -452,6 +453,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 items: lis,
             }),
             Trait(box ast::Trait {
+                constness: rc,
                 is_auto: ra,
                 safety: ru,
                 ident: ri,
@@ -460,7 +462,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 items: ris,
             }),
         ) => {
-            la == ra
+            matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
+                && la == ra
                 && matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
                 && eq_id(*li, *ri)
                 && eq_generics(lg, rg)
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index ce61fffe0de..dc31ed08fb7 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -252,11 +252,11 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
         ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")),
         ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
         ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
-        ItemKind::Trait(_, Safety::Unsafe, ..)
+        ItemKind::Trait(_, _, Safety::Unsafe, ..)
         | ItemKind::Impl(Impl {
             safety: Safety::Unsafe, ..
         }) => (Pat::Str("unsafe"), Pat::Str("}")),
-        ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
+        ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
         ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
         ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")),
         _ => return (Pat::Str(""), Pat::Str("")),
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index ad8c816e204..ff1ee663f9b 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -89,6 +89,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
 
 use itertools::Itertools;
 use rustc_abi::Integer;
+use rustc_ast::join_path_syms;
 use rustc_ast::ast::{self, LitKind, RangeLimits};
 use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
@@ -3245,8 +3246,8 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
                 // a::b::c  ::d::sym refers to
                 // e::f::sym:: ::
                 // result should be super::super::super::super::e::f
-                if let DefPathData::TypeNs(s) = l {
-                    path.push(s.to_string());
+                if let DefPathData::TypeNs(sym) = l {
+                    path.push(sym);
                 }
                 if let DefPathData::TypeNs(_) = r {
                     go_up_by += 1;
@@ -3256,7 +3257,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
             // a::b::sym:: ::    refers to
             // c::d::e  ::f::sym
             // when looking at `f`
-            Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()),
+            Left(DefPathData::TypeNs(sym)) => path.push(sym),
             // consider:
             // a::b::c  ::d::sym refers to
             // e::f::sym:: ::
@@ -3268,17 +3269,17 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
 
     if go_up_by > max_super {
         // `super` chain would be too long, just use the absolute path instead
-        once(String::from("crate"))
-            .chain(to.data.iter().filter_map(|el| {
+        join_path_syms(
+            once(kw::Crate).chain(to.data.iter().filter_map(|el| {
                 if let DefPathData::TypeNs(sym) = el.data {
-                    Some(sym.to_string())
+                    Some(sym)
                 } else {
                     None
                 }
             }))
-            .join("::")
+        )
     } else {
-        repeat_n(String::from("super"), go_up_by).chain(path).join("::")
+        join_path_syms(repeat_n(kw::Super, go_up_by).chain(path))
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 942c71ac33b..b3356450d38 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -432,7 +432,7 @@ pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bo
                     let const_stab_rust_version = match since {
                         StableSince::Version(version) => version,
                         StableSince::Current => RustcVersion::CURRENT,
-                        StableSince::Err => return false,
+                        StableSince::Err(_) => return false,
                     };
 
                     msrv.meets(cx, const_stab_rust_version)
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index 99beea850a2..eee61f949e7 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -84,8 +84,7 @@ mod issue14871 {
         const ONE: Self;
     }
 
-    #[const_trait]
-    pub trait NumberConstants {
+    pub const trait NumberConstants {
         fn constant(value: usize) -> Self;
     }
 
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index 900d5ad38e0..13ffcee0a3c 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -84,8 +84,7 @@ mod issue14871 {
         const ONE: Self;
     }
 
-    #[const_trait]
-    pub trait NumberConstants {
+    pub const trait NumberConstants {
         fn constant(value: usize) -> Self;
     }
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
index f1d5579a723..c113c1caaa6 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
@@ -3,8 +3,7 @@
 
 // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658
 
-#[const_trait]
-trait ConstTrait {
+const trait ConstTrait {
     fn method(self);
 }
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
index d495759526d..69248bc52d5 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
@@ -3,8 +3,7 @@
 
 // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658
 
-#[const_trait]
-trait ConstTrait {
+const trait ConstTrait {
     fn method(self);
 }
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr
index b994b88fac6..7ea009cfc9b 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr
@@ -1,5 +1,5 @@
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/const_trait.rs:24:1
+  --> tests/ui/missing_const_for_fn/const_trait.rs:23:1
    |
 LL | / fn can_be_const() {
 LL | |     0u64.method();
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 65f3f05d6cb..578641e910d 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -312,7 +312,7 @@ mod issue_9218 {
 
     // Inferred to be `&'a str`, afaik.
     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-        //~^ ERROR: lifetime flowing from input to output with different syntax
+        //~^ ERROR: eliding a lifetime that's named elsewhere is confusing
         todo!()
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 600343754e1..fd9ceddfe11 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -231,18 +231,19 @@ error: writing `&String` instead of `&str` involves a new object where a slice w
 LL |     fn good(v1: &String, v2: &String) {
    |                              ^^^^^^^ help: change this to: `&str`
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> tests/ui/ptr_arg.rs:314:36
    |
 LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-   |                                    ^^     ^^           ---- the lifetime gets resolved as `'a`
+   |                                    ^^     ^^           ---- the same lifetime is elided here
    |                                    |      |
-   |                                    |      these lifetimes flow to the output
-   |                                    these lifetimes flow to the output
+   |                                    |      the lifetime is named here
+   |                                    the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
    |                                                         ++
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
index cf52ecf2f03..88ba5f810b4 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
@@ -167,8 +167,7 @@ where
 }
 
 // #13476
-#[const_trait]
-trait ConstTrait {}
+const trait ConstTrait {}
 const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
 
 const fn const_trait_bounds_bad<T: [const] ConstTrait>() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
index 955562f08dc..19a4e70e294 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
@@ -167,8 +167,7 @@ where
 }
 
 // #13476
-#[const_trait]
-trait ConstTrait {}
+const trait ConstTrait {}
 const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {}
 
 const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
index ab31721ef51..a56a683de97 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
@@ -59,19 +59,19 @@ LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) {
    |                                 ^^^^^^^^^^^^^^^^^ help: try: `Any + Send`
 
 error: these bounds contain repeated elements
-  --> tests/ui/trait_duplication_in_bounds.rs:174:36
+  --> tests/ui/trait_duplication_in_bounds.rs:173:36
    |
 LL | const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {}
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait`
 
 error: these where clauses contain repeated elements
-  --> tests/ui/trait_duplication_in_bounds.rs:181:8
+  --> tests/ui/trait_duplication_in_bounds.rs:180:8
    |
 LL |     T: IntoIterator<Item = U::Owned> + IntoIterator<Item = U::Owned>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator<Item = U::Owned>`
 
 error: these where clauses contain repeated elements
-  --> tests/ui/trait_duplication_in_bounds.rs:203:8
+  --> tests/ui/trait_duplication_in_bounds.rs:202:8
    |
 LL |     T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait<ASSOC = 0>`
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 33da1a25db1..12084fa0b15 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! {
@@ -149,6 +175,36 @@ pub enum Sanitizer {
     Hwaddress,
 }
 
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum CodegenBackend {
+    Cranelift,
+    Gcc,
+    Llvm,
+}
+
+impl<'a> TryFrom<&'a str> for CodegenBackend {
+    type Error = &'static str;
+
+    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
+        match value.to_lowercase().as_str() {
+            "cranelift" => Ok(Self::Cranelift),
+            "gcc" => Ok(Self::Gcc),
+            "llvm" => Ok(Self::Llvm),
+            _ => Err("unknown backend"),
+        }
+    }
+}
+
+impl CodegenBackend {
+    pub fn as_str(self) -> &'static str {
+        match self {
+            Self::Cranelift => "cranelift",
+            Self::Gcc => "gcc",
+            Self::Llvm => "llvm",
+        }
+    }
+}
+
 /// Configuration for `compiletest` *per invocation*.
 ///
 /// In terms of `bootstrap`, this means that `./x test tests/ui tests/run-make` actually correspond
@@ -625,6 +681,9 @@ pub struct Config {
     /// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to
     /// `-Zbuild-std`. Used in e.g. ABI tests.
     pub minicore_path: Utf8PathBuf,
+
+    /// Current codegen backend used.
+    pub codegen_backend: CodegenBackend,
 }
 
 impl Config {
@@ -727,6 +786,7 @@ impl Config {
             profiler_runtime: Default::default(),
             diff_command: Default::default(),
             minicore_path: Default::default(),
+            codegen_backend: CodegenBackend::Llvm,
         }
     }
 
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 93133ea0bfd..1397c87ab07 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::{CodegenBackend, 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
         };
@@ -812,6 +818,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-arm-unknown-linux-musleabihf",
     "ignore-auxiliary",
     "ignore-avr",
+    "ignore-backends",
     "ignore-beta",
     "ignore-cdb",
     "ignore-compare-mode-next-solver",
@@ -901,6 +908,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "min-llvm-version",
     "min-system-llvm-version",
     "needs-asm-support",
+    "needs-backends",
     "needs-crate-type",
     "needs-deterministic-layouts",
     "needs-dlltool",
@@ -1007,7 +1015,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",
@@ -1661,6 +1671,8 @@ pub(crate) fn make_test_description<R: Read>(
             decision!(cfg::handle_only(config, ln));
             decision!(needs::handle_needs(&cache.needs, config, ln));
             decision!(ignore_llvm(config, path, ln));
+            decision!(ignore_backends(config, path, ln));
+            decision!(needs_backends(config, path, ln));
             decision!(ignore_cdb(config, ln));
             decision!(ignore_gdb(config, ln));
             decision!(ignore_lldb(config, ln));
@@ -1787,6 +1799,49 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
+fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
+    if let Some(backends_to_ignore) = config.parse_name_value_directive(line, "ignore-backends") {
+        for backend in backends_to_ignore.split_whitespace().map(|backend| {
+            match CodegenBackend::try_from(backend) {
+                Ok(backend) => backend,
+                Err(error) => {
+                    panic!("Invalid ignore-backends value `{backend}` in `{path}`: {error}")
+                }
+            }
+        }) {
+            if config.codegen_backend == backend {
+                return IgnoreDecision::Ignore {
+                    reason: format!("{} backend is marked as ignore", backend.as_str()),
+                };
+            }
+        }
+    }
+    IgnoreDecision::Continue
+}
+
+fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
+    if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends") {
+        if !needed_backends
+            .split_whitespace()
+            .map(|backend| match CodegenBackend::try_from(backend) {
+                Ok(backend) => backend,
+                Err(error) => {
+                    panic!("Invalid needs-backends value `{backend}` in `{path}`: {error}")
+                }
+            })
+            .any(|backend| config.codegen_backend == backend)
+        {
+            return IgnoreDecision::Ignore {
+                reason: format!(
+                    "{} backend is not part of required backends",
+                    config.codegen_backend.as_str()
+                ),
+            };
+        }
+    }
+    IgnoreDecision::Continue
+}
+
 fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
     if let Some(needed_components) =
         config.parse_name_value_directive(line, "needs-llvm-components")
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index f3b3605a120..41bed8ed8a0 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -39,7 +39,7 @@ use walkdir::WalkDir;
 
 use self::directives::{EarlyProps, make_test_description};
 use crate::common::{
-    CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
+    CodegenBackend, CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
     expected_output_path, output_base_dir, output_relative_path,
 };
 use crate::directives::DirectivesCache;
@@ -203,6 +203,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "debugger",
             "only test a specific debugger in debuginfo tests",
             "gdb | lldb | cdb",
+        )
+        .optopt(
+            "",
+            "codegen-backend",
+            "the codegen backend currently used",
+            "CODEGEN BACKEND NAME",
         );
 
     let (argv0, args_) = args.split_first().unwrap();
@@ -264,6 +270,15 @@ pub fn parse_config(args: Vec<String>) -> Config {
             || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
         );
 
+    let codegen_backend = match matches.opt_str("codegen-backend").as_deref() {
+        Some(backend) => match CodegenBackend::try_from(backend) {
+            Ok(backend) => backend,
+            Err(error) => panic!("invalid value `{backend}` for `--codegen-backend`: {error}"),
+        },
+        // By default, it's always llvm.
+        None => CodegenBackend::Llvm,
+    };
+
     let run_ignored = matches.opt_present("ignored");
     let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
     let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions");
@@ -449,6 +464,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
         diff_command: matches.opt_str("compiletest-diff-tool"),
 
         minicore_path: opt_path(matches, "minicore-path"),
+
+        codegen_backend,
     }
 }
 
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/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml
index e914a2df2ba..6e1ab84ed18 100644
--- a/src/tools/lint-docs/Cargo.toml
+++ b/src/tools/lint-docs/Cargo.toml
@@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book."
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-rustc-literal-escaper = "0.0.4"
+rustc-literal-escaper = "0.0.5"
 serde_json = "1.0.57"
 tempfile = "3.1.0"
 walkdir = "2.3.1"
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index 3cc38fa087c..10339928ac2 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -157,7 +157,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.get_alloc_bytes_unchecked_raw(alloc_id)?
                     }
                 }
-                AllocKind::Function | AllocKind::VTable => {
+                AllocKind::Function | AllocKind::Virtual => {
                     // Allocate some dummy memory to get a unique address for this function/vtable.
                     let alloc_bytes = MiriAllocBytes::from_bytes(
                         &[0u8; 1],
diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs
index 459acea6f0b..5a96633c99e 100644
--- a/src/tools/miri/src/bin/log/tracing_chrome.rs
+++ b/src/tools/miri/src/bin/log/tracing_chrome.rs
@@ -1,8 +1,18 @@
 // SPDX-License-Identifier: MIT
 // SPDX-FileCopyrightText: Copyright (c) 2020 Thoren Paulson
-//! This file is taken unmodified from the following link, except for file attributes and
-//! `extern crate` at the top.
-//! https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs
+//! This file was initially taken from the following link:
+//! <https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs>
+//!
+//! The precise changes that were made to the original file can be found in git history
+//! (`git log -- path/to/tracing_chrome.rs`), but in summary:
+//! - the file attributes were changed and `extern crate` was added at the top
+//! - if a tracing span has a field called "tracing_separate_thread", it will be given a separate
+//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing
+//! the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior:
+//!   ```rust
+//!   tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */)
+//!   ```
+//!
 //! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it
 //! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would
 //! not be possible to use the [ChromeLayer] in a context that expects a [Layer] from
@@ -79,14 +89,26 @@ where
 }
 
 /// Decides how traces will be recorded.
+/// Also see <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1>
 #[derive(Default)]
 pub enum TraceStyle {
-    /// Traces will be recorded as a group of threads.
+    /// Traces will be recorded as a group of threads, and all spans on the same thread will appear
+    /// on a single trace line in <https://ui.perfetto.dev>.
     /// In this style, spans should be entered and exited on the same thread.
+    ///
+    /// If a tracing span has a field called "tracing_separate_thread", it will be given a separate
+    /// span ID even in this mode, to make it appear on a separate line when viewing the trace in
+    /// <https://ui.perfetto.dev>. This is the syntax to trigger this behavior:
+    /// ```rust
+    /// tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */)
+    /// ```
+    /// [tracing::field::Empty] is used so that other tracing layers (e.g. the logger) will ignore
+    /// the "tracing_separate_thread" argument and not print out anything for it.
     #[default]
     Threaded,
 
-    /// Traces will recorded as a group of asynchronous operations.
+    /// Traces will recorded as a group of asynchronous operations. All spans will be given separate
+    /// span IDs and will appear on separate trace lines in <https://ui.perfetto.dev>.
     Async,
 }
 
@@ -497,31 +519,39 @@ where
         }
     }
 
-    fn get_root_id(span: SpanRef<S>) -> u64 {
-        span.scope()
-            .from_root()
-            .take(1)
-            .next()
-            .unwrap_or(span)
-            .id()
-            .into_u64()
+    fn get_root_id(&self, span: SpanRef<S>) -> Option<u64> {
+        match self.trace_style {
+            TraceStyle::Threaded => {
+                if span.fields().field("tracing_separate_thread").is_some() {
+                    // assign an independent "id" to spans with argument "tracing_separate_thread",
+                    // so they appear a separate trace line in trace visualization tools, see
+                    // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1
+                    Some(span.id().into_u64())
+                } else {
+                    None
+                }
+            },
+            TraceStyle::Async => Some(
+                span.scope()
+                    .from_root()
+                    .take(1)
+                    .next()
+                    .unwrap_or(span)
+                    .id()
+                    .into_u64()
+            ),
+        }
     }
 
     fn enter_span(&self, span: SpanRef<S>, ts: f64) {
         let callsite = self.get_callsite(EventOrSpan::Span(&span));
-        let root_id = match self.trace_style {
-            TraceStyle::Async => Some(ChromeLayer::get_root_id(span)),
-            _ => None,
-        };
+        let root_id = self.get_root_id(span);
         self.send_message(Message::Enter(ts, callsite, root_id));
     }
 
     fn exit_span(&self, span: SpanRef<S>, ts: f64) {
         let callsite = self.get_callsite(EventOrSpan::Span(&span));
-        let root_id = match self.trace_style {
-            TraceStyle::Async => Some(ChromeLayer::get_root_id(span)),
-            _ => None,
-        };
+        let root_id = self.get_root_id(span);
         self.send_message(Message::Exit(ts, callsite, root_id));
     }
 
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 834a4b41f22..e834fdffdd1 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -650,7 +650,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                         dcx.log_protector();
                     }
                 },
-                AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
+                AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => {
                     // No stacked borrows on these allocations.
                 }
             }
@@ -1021,7 +1021,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
                 alloc_extra.borrow_tracker_sb().borrow_mut().exposed_tags.insert(tag);
             }
-            AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
+            AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => {
                 // No stacked borrows on these allocations.
             }
         }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index c157c69d7c8..aa92f8a8c30 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -673,7 +673,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}");
                 alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag);
             }
-            AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
+            AllocKind::Function | AllocKind::Virtual | AllocKind::Dead => {
                 // No tree borrows on these allocations.
             }
         }
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 9c077e5b7b6..f309e34c75b 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1086,7 +1086,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &MiriInterpCx<'tcx>,
         instance: ty::Instance<'tcx>,
     ) -> InterpResult<'tcx> {
-        let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id());
+        let attrs = ecx.tcx.codegen_instance_attrs(instance.def);
         if attrs
             .target_features
             .iter()
@@ -1790,7 +1790,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                 ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
                 InliningThreshold::Always
             ) || !matches!(
-                ecx.tcx.codegen_fn_attrs(instance.def_id()).inline,
+                ecx.tcx.codegen_instance_attrs(instance.def).inline,
                 InlineAttr::Never
             );
             !is_generic && !can_be_inlined
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/panic/mir-validation.stderr b/src/tools/miri/tests/panic/mir-validation.stderr
index dc70d129da3..f801ac907e6 100644
--- a/src/tools/miri/tests/panic/mir-validation.stderr
+++ b/src/tools/miri/tests/panic/mir-validation.stderr
@@ -1,11 +1,15 @@
+error: internal compiler error: compiler/rustc_mir_transform/src/validate.rs:LL:CC: broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
+                                place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
+  --> tests/panic/mir-validation.rs:LL:CC
+   |
+LL |             *(tuple.0) = 1;
+   |             ^^^^^^^^^^^^^^
+
 
 thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:
-broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
-place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
+Box<dyn Any>
 stack backtrace:
 
-error: the compiler unexpectedly panicked. this is a bug.
-
 
 
 
@@ -20,3 +24,5 @@ LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 
+error: aborting due to 1 previous error
+
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/miri/tests/pass/intrinsics/type-id.rs b/src/tools/miri/tests/pass/intrinsics/type-id.rs
new file mode 100644
index 00000000000..123fdbdc9ce
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics/type-id.rs
@@ -0,0 +1,19 @@
+use std::any::{Any, TypeId};
+
+fn main() {
+    let t1 = TypeId::of::<u64>();
+    let t2 = TypeId::of::<u64>();
+    assert_eq!(t1, t2);
+    let t3 = TypeId::of::<usize>();
+    assert_ne!(t1, t3);
+
+    let _ = format!("{t1:?}"); // test that we can debug-print
+
+    let b = Box::new(0u64) as Box<dyn Any>;
+    assert_eq!(*b.downcast_ref::<u64>().unwrap(), 0);
+    assert!(b.downcast_ref::<usize>().is_none());
+
+    // Get the first pointer chunk and try to make it a ZST ref.
+    // This used to trigger an error because TypeId allocs got misclassified as "LiveData".
+    let _raw_chunk = unsafe { (&raw const t1).cast::<&()>().read() };
+}
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/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 7432a82080d..e55cd80943d 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -154,6 +154,22 @@ dependencies = [
 ]
 
 [[package]]
+name = "cargo-util-schemas"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dc1a6f7b5651af85774ae5a34b4e8be397d9cf4bc063b7e6dbd99a841837830"
+dependencies = [
+ "semver",
+ "serde",
+ "serde-untagged",
+ "serde-value",
+ "thiserror 2.0.12",
+ "toml",
+ "unicode-xid",
+ "url",
+]
+
+[[package]]
 name = "cargo_metadata"
 version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -161,7 +177,22 @@ checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502"
 dependencies = [
  "camino",
  "cargo-platform",
- "cargo-util-schemas",
+ "cargo-util-schemas 0.2.0",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.12",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cfca2aaa699835ba88faf58a06342a314a950d2b9686165e038286c30316868"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "cargo-util-schemas 0.8.2",
  "semver",
  "serde",
  "serde_json",
@@ -1190,13 +1221,16 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 name = "lsp-server"
 version = "0.7.8"
 dependencies = [
+ "anyhow",
  "crossbeam-channel",
  "ctrlc",
  "log",
  "lsp-types",
+ "rustc-hash 2.1.1",
  "serde",
  "serde_derive",
  "serde_json",
+ "toolchain",
 ]
 
 [[package]]
@@ -1471,7 +1505,7 @@ dependencies = [
  "edition",
  "expect-test",
  "ra-ap-rustc_lexer",
- "rustc-literal-escaper 0.0.4",
+ "rustc-literal-escaper",
  "stdx",
  "tracing",
 ]
@@ -1599,7 +1633,7 @@ dependencies = [
 name = "proc-macro-test"
 version = "0.0.0"
 dependencies = [
- "cargo_metadata",
+ "cargo_metadata 0.20.0",
 ]
 
 [[package]]
@@ -1640,7 +1674,7 @@ version = "0.0.0"
 dependencies = [
  "anyhow",
  "base-db",
- "cargo_metadata",
+ "cargo_metadata 0.21.0",
  "cfg",
  "expect-test",
  "intern",
@@ -1722,9 +1756,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a967e3a9cd3e38b543f503978e0eccee461e3aea3f7b10e944959bff41dbe612"
+checksum = "3ee51482d1c9d3e538acda8cce723db8eea1a81540544bf362bf4c3d841b2329"
 dependencies = [
  "bitflags 2.9.1",
  "ra-ap-rustc_hashes",
@@ -1734,18 +1768,18 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_hashes"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ea4c755ecbbffa5743c251344f484ebe571ec7bc5b36d80b2a8ae775d1a7a40"
+checksum = "19c8f1e0c28e24e1b4c55dc08058c6c9829df2204497d4034259f491d348c204"
 dependencies = [
  "rustc-stable-hash",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aca7ad7cf911538c619caa2162339fe98637e9e46f11bb0484ef96735df4d64a"
+checksum = "5f33f429cec6b92fa2c7243883279fb29dd233fdc3e94099aff32aa91aa87f50"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1753,9 +1787,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8767ba551c9355bc3031be072cc4bb0381106e5e7cd275e72b7a8c76051c4070"
+checksum = "b9b55910dbe1fe7ef34bdc1d1bcb41e99b377eb680ea58a1218d95d6b4152257"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1764,9 +1798,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6101374afb267e6c27e4e2eb0b1352e9f3504c1a8f716f619cd39244e2ed92ab"
+checksum = "22944e31fb91e9b3e75bcbc91e37d958b8c0825a6160927f2856831d2ce83b36"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1775,19 +1809,19 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecd88a19f00da4f43e6727d5013444cbc399804b5046dfa2bbcd28ebed3970ce"
+checksum = "81057891bc2063ad9e353f29462fbc47a0f5072560af34428ae9313aaa5e9d97"
 dependencies = [
  "ra-ap-rustc_lexer",
- "rustc-literal-escaper 0.0.2",
+ "rustc-literal-escaper",
 ]
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.116.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb332dd32d7850a799862533b1c021e6062558861a4ad57817bf522499fbb892"
+checksum = "fe21a3542980d56d2435e96c2720773cac1c63fd4db666417e414729da192eb3"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.1.1",
@@ -1855,7 +1889,7 @@ version = "0.0.0"
 dependencies = [
  "anyhow",
  "base64",
- "cargo_metadata",
+ "cargo_metadata 0.21.0",
  "cfg",
  "crossbeam-channel",
  "dirs",
@@ -1934,12 +1968,6 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
 
 [[package]]
 name = "rustc-literal-escaper"
-version = "0.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
-
-[[package]]
-name = "rustc-literal-escaper"
 version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b"
@@ -2231,7 +2259,7 @@ dependencies = [
  "rayon",
  "rowan",
  "rustc-hash 2.1.1",
- "rustc-literal-escaper 0.0.4",
+ "rustc-literal-escaper",
  "rustc_apfloat",
  "smol_str",
  "stdx",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index d268ce5b0bb..41fa06a76a7 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.86"
+rust-version = "1.88"
 edition = "2024"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
@@ -89,11 +89,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 edition = { path = "./crates/edition", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.116", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.116", default-features = false }
-ra-ap-rustc_index = { version = "0.116", default-features = false }
-ra-ap-rustc_abi = { version = "0.116", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.116", default-features = false }
+ra-ap-rustc_lexer = { version = "0.121", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.121", default-features = false }
+ra-ap-rustc_index = { version = "0.121", default-features = false }
+ra-ap-rustc_abi = { version = "0.121", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.121", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
@@ -106,7 +106,7 @@ lsp-server = { version = "0.7.8" }
 anyhow = "1.0.98"
 arrayvec = "0.7.6"
 bitflags = "2.9.1"
-cargo_metadata = "0.20.0"
+cargo_metadata = "0.21.0"
 camino = "1.1.10"
 chalk-solve = { version = "0.103.0", default-features = false }
 chalk-ir = "0.103.0"
@@ -138,7 +138,11 @@ rayon = "1.10.0"
 rowan = "=0.15.15"
 # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
 # on impls without it
-salsa = { version = "0.23.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] }
+salsa = { version = "0.23.0", default-features = true, features = [
+  "rayon",
+  "salsa_unstable",
+  "macros",
+] }
 salsa-macros = "0.23.0"
 semver = "1.0.26"
 serde = { version = "1.0.219" }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index 51612f341a1..d3dfc05eb29 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -22,6 +22,7 @@ use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::{Edition, SyntaxContext};
 use syntax::{AstPtr, SyntaxNodePtr, ast};
+use thin_vec::ThinVec;
 use triomphe::Arc;
 use tt::TextRange;
 
@@ -93,17 +94,17 @@ pub type TypeSource = InFile<TypePtr>;
 pub type LifetimePtr = AstPtr<ast::Lifetime>;
 pub type LifetimeSource = InFile<LifetimePtr>;
 
+// We split the store into types-only and expressions, because most stores (e.g. generics)
+// don't store any expressions and this saves memory. Same thing for the source map.
 #[derive(Debug, PartialEq, Eq)]
-pub struct ExpressionStore {
-    pub exprs: Arena<Expr>,
-    pub pats: Arena<Pat>,
-    pub bindings: Arena<Binding>,
-    pub labels: Arena<Label>,
-    pub types: Arena<TypeRef>,
-    pub lifetimes: Arena<LifetimeRef>,
+struct ExpressionOnlyStore {
+    exprs: Arena<Expr>,
+    pats: Arena<Pat>,
+    bindings: Arena<Binding>,
+    labels: Arena<Label>,
     /// Id of the closure/coroutine that owns the corresponding binding. If a binding is owned by the
     /// top level expression, it will not be listed in here.
-    pub binding_owners: FxHashMap<BindingId, ExprId>,
+    binding_owners: FxHashMap<BindingId, ExprId>,
     /// Block expressions in this store that may contain inner items.
     block_scopes: Box<[BlockId]>,
 
@@ -114,8 +115,15 @@ pub struct ExpressionStore {
     ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
 }
 
+#[derive(Debug, PartialEq, Eq)]
+pub struct ExpressionStore {
+    expr_only: Option<Box<ExpressionOnlyStore>>,
+    pub types: Arena<TypeRef>,
+    pub lifetimes: Arena<LifetimeRef>,
+}
+
 #[derive(Debug, Eq, Default)]
-pub struct ExpressionStoreSourceMap {
+struct ExpressionOnlySourceMap {
     // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
     // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
     expr_map: FxHashMap<ExprSource, ExprOrPatId>,
@@ -127,12 +135,6 @@ pub struct ExpressionStoreSourceMap {
     label_map: FxHashMap<LabelSource, LabelId>,
     label_map_back: ArenaMap<LabelId, LabelSource>,
 
-    types_map_back: ArenaMap<TypeRefId, TypeSource>,
-    types_map: FxHashMap<TypeSource, TypeRefId>,
-
-    lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
-    lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
-
     binding_definitions:
         ArenaMap<BindingId, SmallVec<[PatId; 2 * size_of::<usize>() / size_of::<PatId>()]>>,
 
@@ -143,14 +145,17 @@ pub struct ExpressionStoreSourceMap {
 
     template_map: Option<Box<FormatTemplate>>,
 
-    pub expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
+    expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
 
     /// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in
     /// the source map (since they're just as volatile).
-    pub diagnostics: Vec<ExpressionStoreDiagnostics>,
+    //
+    // We store diagnostics on the `ExpressionOnlySourceMap` because diagnostics are rare (except
+    // maybe for cfgs, and they are also not common in type places).
+    diagnostics: ThinVec<ExpressionStoreDiagnostics>,
 }
 
-impl PartialEq for ExpressionStoreSourceMap {
+impl PartialEq for ExpressionOnlySourceMap {
     fn eq(&self, other: &Self) -> bool {
         // we only need to compare one of the two mappings
         // as the other is a reverse mapping and thus will compare
@@ -162,10 +167,6 @@ impl PartialEq for ExpressionStoreSourceMap {
             pat_map_back,
             label_map: _,
             label_map_back,
-            types_map_back,
-            types_map: _,
-            lifetime_map_back,
-            lifetime_map: _,
             // If this changed, our pattern data must have changed
             binding_definitions: _,
             // If this changed, our expression data must have changed
@@ -179,14 +180,40 @@ impl PartialEq for ExpressionStoreSourceMap {
         *expr_map_back == other.expr_map_back
             && *pat_map_back == other.pat_map_back
             && *label_map_back == other.label_map_back
-            && *types_map_back == other.types_map_back
-            && *lifetime_map_back == other.lifetime_map_back
             && *template_map == other.template_map
             && *expansions == other.expansions
             && *diagnostics == other.diagnostics
     }
 }
 
+#[derive(Debug, Eq, Default)]
+pub struct ExpressionStoreSourceMap {
+    expr_only: Option<Box<ExpressionOnlySourceMap>>,
+
+    types_map_back: ArenaMap<TypeRefId, TypeSource>,
+    types_map: FxHashMap<TypeSource, TypeRefId>,
+
+    lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
+    #[expect(
+        unused,
+        reason = "this is here for completeness, and maybe we'll need it in the future"
+    )]
+    lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
+}
+
+impl PartialEq for ExpressionStoreSourceMap {
+    fn eq(&self, other: &Self) -> bool {
+        // we only need to compare one of the two mappings
+        // as the other is a reverse mapping and thus will compare
+        // the same as normal mapping
+        let Self { expr_only, types_map_back, types_map: _, lifetime_map_back, lifetime_map: _ } =
+            self;
+        *expr_only == other.expr_only
+            && *types_map_back == other.types_map_back
+            && *lifetime_map_back == other.lifetime_map_back
+    }
+}
+
 /// The body of an item (function, const etc.).
 #[derive(Debug, Eq, PartialEq, Default)]
 pub struct ExpressionStoreBuilder {
@@ -199,6 +226,42 @@ pub struct ExpressionStoreBuilder {
     pub types: Arena<TypeRef>,
     block_scopes: Vec<BlockId>,
     ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
+
+    // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
+    // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
+    expr_map: FxHashMap<ExprSource, ExprOrPatId>,
+    expr_map_back: ArenaMap<ExprId, ExprOrPatSource>,
+
+    pat_map: FxHashMap<PatSource, ExprOrPatId>,
+    pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
+
+    label_map: FxHashMap<LabelSource, LabelId>,
+    label_map_back: ArenaMap<LabelId, LabelSource>,
+
+    types_map_back: ArenaMap<TypeRefId, TypeSource>,
+    types_map: FxHashMap<TypeSource, TypeRefId>,
+
+    lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
+    lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
+
+    binding_definitions:
+        ArenaMap<BindingId, SmallVec<[PatId; 2 * size_of::<usize>() / size_of::<PatId>()]>>,
+
+    /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
+    /// Instead, we use id of expression (`92`) to identify the field.
+    field_map_back: FxHashMap<ExprId, FieldSource>,
+    pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
+
+    template_map: Option<Box<FormatTemplate>>,
+
+    expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
+
+    /// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in
+    /// the source map (since they're just as volatile).
+    //
+    // We store diagnostics on the `ExpressionOnlySourceMap` because diagnostics are rare (except
+    // maybe for cfgs, and they are also not common in type places).
+    pub(crate) diagnostics: Vec<ExpressionStoreDiagnostics>,
 }
 
 #[derive(Default, Debug, Eq, PartialEq)]
@@ -226,7 +289,7 @@ pub enum ExpressionStoreDiagnostics {
 }
 
 impl ExpressionStoreBuilder {
-    pub fn finish(self) -> ExpressionStore {
+    pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) {
         let Self {
             block_scopes,
             mut exprs,
@@ -237,6 +300,23 @@ impl ExpressionStoreBuilder {
             mut ident_hygiene,
             mut types,
             mut lifetimes,
+
+            mut expr_map,
+            mut expr_map_back,
+            mut pat_map,
+            mut pat_map_back,
+            mut label_map,
+            mut label_map_back,
+            mut types_map_back,
+            mut types_map,
+            mut lifetime_map_back,
+            mut lifetime_map,
+            mut binding_definitions,
+            mut field_map_back,
+            mut pat_field_map_back,
+            mut template_map,
+            mut expansions,
+            diagnostics,
         } = self;
         exprs.shrink_to_fit();
         labels.shrink_to_fit();
@@ -247,24 +327,90 @@ impl ExpressionStoreBuilder {
         types.shrink_to_fit();
         lifetimes.shrink_to_fit();
 
-        ExpressionStore {
-            exprs,
-            pats,
-            bindings,
-            labels,
-            binding_owners,
-            types,
-            lifetimes,
-            block_scopes: block_scopes.into_boxed_slice(),
-            ident_hygiene,
+        expr_map.shrink_to_fit();
+        expr_map_back.shrink_to_fit();
+        pat_map.shrink_to_fit();
+        pat_map_back.shrink_to_fit();
+        label_map.shrink_to_fit();
+        label_map_back.shrink_to_fit();
+        types_map_back.shrink_to_fit();
+        types_map.shrink_to_fit();
+        lifetime_map_back.shrink_to_fit();
+        lifetime_map.shrink_to_fit();
+        binding_definitions.shrink_to_fit();
+        field_map_back.shrink_to_fit();
+        pat_field_map_back.shrink_to_fit();
+        if let Some(template_map) = &mut template_map {
+            let FormatTemplate {
+                format_args_to_captures,
+                asm_to_captures,
+                implicit_capture_to_source,
+            } = &mut **template_map;
+            format_args_to_captures.shrink_to_fit();
+            asm_to_captures.shrink_to_fit();
+            implicit_capture_to_source.shrink_to_fit();
         }
+        expansions.shrink_to_fit();
+
+        let has_exprs =
+            !exprs.is_empty() || !labels.is_empty() || !pats.is_empty() || !bindings.is_empty();
+
+        let store = {
+            let expr_only = if has_exprs {
+                Some(Box::new(ExpressionOnlyStore {
+                    exprs,
+                    pats,
+                    bindings,
+                    labels,
+                    binding_owners,
+                    block_scopes: block_scopes.into_boxed_slice(),
+                    ident_hygiene,
+                }))
+            } else {
+                None
+            };
+            ExpressionStore { expr_only, types, lifetimes }
+        };
+
+        let source_map = {
+            let expr_only = if has_exprs || !expansions.is_empty() || !diagnostics.is_empty() {
+                Some(Box::new(ExpressionOnlySourceMap {
+                    expr_map,
+                    expr_map_back,
+                    pat_map,
+                    pat_map_back,
+                    label_map,
+                    label_map_back,
+                    binding_definitions,
+                    field_map_back,
+                    pat_field_map_back,
+                    template_map,
+                    expansions,
+                    diagnostics: ThinVec::from_iter(diagnostics),
+                }))
+            } else {
+                None
+            };
+            ExpressionStoreSourceMap {
+                expr_only,
+                types_map_back,
+                types_map,
+                lifetime_map_back,
+                lifetime_map,
+            }
+        };
+
+        (store, source_map)
     }
 }
 
 impl ExpressionStore {
-    pub fn empty_singleton() -> Arc<Self> {
-        static EMPTY: LazyLock<Arc<ExpressionStore>> =
-            LazyLock::new(|| Arc::new(ExpressionStoreBuilder::default().finish()));
+    pub fn empty_singleton() -> (Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>) {
+        static EMPTY: LazyLock<(Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>)> =
+            LazyLock::new(|| {
+                let (store, source_map) = ExpressionStoreBuilder::default().finish();
+                (Arc::new(store), Arc::new(source_map))
+            });
         EMPTY.clone()
     }
 
@@ -273,7 +419,12 @@ impl ExpressionStore {
         &'a self,
         db: &'a dyn DefDatabase,
     ) -> impl Iterator<Item = (BlockId, &'a DefMap)> + 'a {
-        self.block_scopes.iter().map(move |&block| (block, block_def_map(db, block)))
+        self.expr_only
+            .as_ref()
+            .map(|it| &*it.block_scopes)
+            .unwrap_or_default()
+            .iter()
+            .map(move |&block| (block, block_def_map(db, block)))
     }
 
     pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -320,7 +471,8 @@ impl ExpressionStore {
     }
 
     pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool {
-        match self.binding_owners.get(&binding) {
+        let Some(expr_only) = &self.expr_only else { return false };
+        match expr_only.binding_owners.get(&binding) {
             Some(it) => {
                 // We assign expression ids in a way that outer closures will receive
                 // a lower id
@@ -330,6 +482,11 @@ impl ExpressionStore {
         }
     }
 
+    #[inline]
+    pub fn binding_owner(&self, id: BindingId) -> Option<ExprId> {
+        self.expr_only.as_ref()?.binding_owners.get(&id).copied()
+    }
+
     /// Walks the immediate children expressions and calls `f` for each child expression.
     ///
     /// Note that this does not walk const blocks.
@@ -601,16 +758,22 @@ impl ExpressionStore {
         });
     }
 
+    #[inline]
+    #[track_caller]
+    fn assert_expr_only(&self) -> &ExpressionOnlyStore {
+        self.expr_only.as_ref().expect("should have `ExpressionStore::expr_only`")
+    }
+
     fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
-        self.bindings[binding].hygiene
+        self.assert_expr_only().bindings[binding].hygiene
     }
 
     pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
-        self.ident_hygiene.get(&expr.into()).copied().unwrap_or(HygieneId::ROOT)
+        self.assert_expr_only().ident_hygiene.get(&expr.into()).copied().unwrap_or(HygieneId::ROOT)
     }
 
     pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
-        self.ident_hygiene.get(&pat.into()).copied().unwrap_or(HygieneId::ROOT)
+        self.assert_expr_only().ident_hygiene.get(&pat.into()).copied().unwrap_or(HygieneId::ROOT)
     }
 
     pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
@@ -619,43 +782,72 @@ impl ExpressionStore {
             ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
         }
     }
+
+    #[inline]
+    pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> {
+        match &self.expr_only {
+            Some(it) => it.exprs.iter(),
+            None => const { &Arena::new() }.iter(),
+        }
+    }
+
+    #[inline]
+    pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> {
+        match &self.expr_only {
+            Some(it) => it.pats.iter(),
+            None => const { &Arena::new() }.iter(),
+        }
+    }
+
+    #[inline]
+    pub fn bindings(&self) -> impl Iterator<Item = (BindingId, &Binding)> {
+        match &self.expr_only {
+            Some(it) => it.bindings.iter(),
+            None => const { &Arena::new() }.iter(),
+        }
+    }
 }
 
 impl Index<ExprId> for ExpressionStore {
     type Output = Expr;
 
+    #[inline]
     fn index(&self, expr: ExprId) -> &Expr {
-        &self.exprs[expr]
+        &self.assert_expr_only().exprs[expr]
     }
 }
 
 impl Index<PatId> for ExpressionStore {
     type Output = Pat;
 
+    #[inline]
     fn index(&self, pat: PatId) -> &Pat {
-        &self.pats[pat]
+        &self.assert_expr_only().pats[pat]
     }
 }
 
 impl Index<LabelId> for ExpressionStore {
     type Output = Label;
 
+    #[inline]
     fn index(&self, label: LabelId) -> &Label {
-        &self.labels[label]
+        &self.assert_expr_only().labels[label]
     }
 }
 
 impl Index<BindingId> for ExpressionStore {
     type Output = Binding;
 
+    #[inline]
     fn index(&self, b: BindingId) -> &Binding {
-        &self.bindings[b]
+        &self.assert_expr_only().bindings[b]
     }
 }
 
 impl Index<TypeRefId> for ExpressionStore {
     type Output = TypeRef;
 
+    #[inline]
     fn index(&self, b: TypeRefId) -> &TypeRef {
         &self.types[b]
     }
@@ -664,6 +856,7 @@ impl Index<TypeRefId> for ExpressionStore {
 impl Index<LifetimeRefId> for ExpressionStore {
     type Output = LifetimeRef;
 
+    #[inline]
     fn index(&self, b: LifetimeRefId) -> &LifetimeRef {
         &self.lifetimes[b]
     }
@@ -684,12 +877,6 @@ impl Index<PathId> for ExpressionStore {
 // FIXME: Change `node_` prefix to something more reasonable.
 // Perhaps `expr_syntax` and `expr_id`?
 impl ExpressionStoreSourceMap {
-    pub fn empty_singleton() -> Arc<Self> {
-        static EMPTY: LazyLock<Arc<ExpressionStoreSourceMap>> =
-            LazyLock::new(|| Arc::new(ExpressionStoreSourceMap::default()));
-        EMPTY.clone()
-    }
-
     pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
         match id {
             ExprOrPatId::ExprId(id) => self.expr_syntax(id),
@@ -697,30 +884,46 @@ impl ExpressionStoreSourceMap {
         }
     }
 
+    #[inline]
+    fn expr_or_synthetic(&self) -> Result<&ExpressionOnlySourceMap, SyntheticSyntax> {
+        self.expr_only.as_deref().ok_or(SyntheticSyntax)
+    }
+
+    #[inline]
+    fn expr_only(&self) -> Option<&ExpressionOnlySourceMap> {
+        self.expr_only.as_deref()
+    }
+
+    #[inline]
+    #[track_caller]
+    fn assert_expr_only(&self) -> &ExpressionOnlySourceMap {
+        self.expr_only.as_ref().expect("should have `ExpressionStoreSourceMap::expr_only`")
+    }
+
     pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprOrPatSource, SyntheticSyntax> {
-        self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
+        self.expr_or_synthetic()?.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
     }
 
     pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
         let src = node.map(AstPtr::new);
-        self.expr_map.get(&src).cloned()
+        self.expr_only()?.expr_map.get(&src).cloned()
     }
 
     pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
         let src = node.map(AstPtr::new);
-        self.expansions.get(&src).cloned()
+        self.expr_only()?.expansions.get(&src).cloned()
     }
 
     pub fn macro_calls(&self) -> impl Iterator<Item = (InFile<MacroCallPtr>, MacroCallId)> + '_ {
-        self.expansions.iter().map(|(&a, &b)| (a, b))
+        self.expr_only().into_iter().flat_map(|it| it.expansions.iter().map(|(&a, &b)| (a, b)))
     }
 
     pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
-        self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
+        self.expr_or_synthetic()?.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
 
     pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<ExprOrPatId> {
-        self.pat_map.get(&node.map(AstPtr::new)).cloned()
+        self.expr_only()?.pat_map.get(&node.map(AstPtr::new)).cloned()
     }
 
     pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
@@ -732,49 +935,50 @@ impl ExpressionStoreSourceMap {
     }
 
     pub fn label_syntax(&self, label: LabelId) -> LabelSource {
-        self.label_map_back[label]
+        self.assert_expr_only().label_map_back[label]
     }
 
     pub fn patterns_for_binding(&self, binding: BindingId) -> &[PatId] {
-        self.binding_definitions.get(binding).map_or(&[], Deref::deref)
+        self.assert_expr_only().binding_definitions.get(binding).map_or(&[], Deref::deref)
     }
 
     pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
         let src = node.map(AstPtr::new);
-        self.label_map.get(&src).cloned()
+        self.expr_only()?.label_map.get(&src).cloned()
     }
 
     pub fn field_syntax(&self, expr: ExprId) -> FieldSource {
-        self.field_map_back[&expr]
+        self.assert_expr_only().field_map_back[&expr]
     }
 
     pub fn pat_field_syntax(&self, pat: PatId) -> PatFieldSource {
-        self.pat_field_map_back[&pat]
+        self.assert_expr_only().pat_field_map_back[&pat]
     }
 
     pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
         let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
-        self.expr_map.get(&src).copied()
+        self.expr_only()?.expr_map.get(&src).copied()
     }
 
     pub fn expansions(&self) -> impl Iterator<Item = (&InFile<MacroCallPtr>, &MacroCallId)> {
-        self.expansions.iter()
+        self.expr_only().into_iter().flat_map(|it| it.expansions.iter())
     }
 
     pub fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
-        self.expansions.get(&node.map(AstPtr::new)).copied()
+        self.expr_only()?.expansions.get(&node.map(AstPtr::new)).copied()
     }
 
     pub fn implicit_format_args(
         &self,
         node: InFile<&ast::FormatArgsExpr>,
     ) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
+        let expr_only = self.expr_only()?;
         let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
-        let (hygiene, names) = self
+        let (hygiene, names) = expr_only
             .template_map
             .as_ref()?
             .format_args_to_captures
-            .get(&self.expr_map.get(&src)?.as_expr()?)?;
+            .get(&expr_only.expr_map.get(&src)?.as_expr()?)?;
         Some((*hygiene, &**names))
     }
 
@@ -782,67 +986,28 @@ impl ExpressionStoreSourceMap {
         &self,
         capture_expr: ExprId,
     ) -> Option<InFile<(ExprPtr, TextRange)>> {
-        self.template_map.as_ref()?.implicit_capture_to_source.get(&capture_expr).copied()
+        self.expr_only()?
+            .template_map
+            .as_ref()?
+            .implicit_capture_to_source
+            .get(&capture_expr)
+            .copied()
     }
 
     pub fn asm_template_args(
         &self,
         node: InFile<&ast::AsmExpr>,
     ) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
+        let expr_only = self.expr_only()?;
         let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
-        let expr = self.expr_map.get(&src)?.as_expr()?;
-        Some(expr)
-            .zip(self.template_map.as_ref()?.asm_to_captures.get(&expr).map(std::ops::Deref::deref))
+        let expr = expr_only.expr_map.get(&src)?.as_expr()?;
+        Some(expr).zip(
+            expr_only.template_map.as_ref()?.asm_to_captures.get(&expr).map(std::ops::Deref::deref),
+        )
     }
 
     /// Get a reference to the source map's diagnostics.
     pub fn diagnostics(&self) -> &[ExpressionStoreDiagnostics] {
-        &self.diagnostics
-    }
-
-    fn shrink_to_fit(&mut self) {
-        let Self {
-            expr_map,
-            expr_map_back,
-            pat_map,
-            pat_map_back,
-            label_map,
-            label_map_back,
-            field_map_back,
-            pat_field_map_back,
-            expansions,
-            template_map,
-            diagnostics,
-            binding_definitions,
-            types_map,
-            types_map_back,
-            lifetime_map_back,
-            lifetime_map,
-        } = self;
-        if let Some(template_map) = template_map {
-            let FormatTemplate {
-                format_args_to_captures,
-                asm_to_captures,
-                implicit_capture_to_source,
-            } = &mut **template_map;
-            format_args_to_captures.shrink_to_fit();
-            asm_to_captures.shrink_to_fit();
-            implicit_capture_to_source.shrink_to_fit();
-        }
-        expr_map.shrink_to_fit();
-        expr_map_back.shrink_to_fit();
-        pat_map.shrink_to_fit();
-        pat_map_back.shrink_to_fit();
-        label_map.shrink_to_fit();
-        label_map_back.shrink_to_fit();
-        field_map_back.shrink_to_fit();
-        pat_field_map_back.shrink_to_fit();
-        expansions.shrink_to_fit();
-        diagnostics.shrink_to_fit();
-        binding_definitions.shrink_to_fit();
-        types_map.shrink_to_fit();
-        types_map_back.shrink_to_fit();
-        lifetime_map.shrink_to_fit();
-        lifetime_map_back.shrink_to_fit();
+        self.expr_only().map(|it| &*it.diagnostics).unwrap_or_default()
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs
index fb6d931e0e4..c955393b9cf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs
@@ -36,6 +36,7 @@ pub struct Body {
 impl ops::Deref for Body {
     type Target = ExpressionStore;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.store
     }
@@ -61,6 +62,7 @@ pub struct BodySourceMap {
 impl ops::Deref for BodySourceMap {
     type Target = ExpressionStoreSourceMap;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.store
     }
@@ -102,9 +104,7 @@ impl Body {
             }
         };
         let module = def.module(db);
-        let (body, mut source_map) =
-            lower_body(db, def, file_id, module, params, body, is_async_fn);
-        source_map.store.shrink_to_fit();
+        let (body, source_map) = lower_body(db, def, file_id, module, params, body, is_async_fn);
 
         (Arc::new(body), Arc::new(source_map))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index c0e51b338b4..4e877748ca2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -121,14 +121,10 @@ pub(super) fn lower_body(
             params = (0..count).map(|_| collector.missing_pat()).collect();
         };
         let body_expr = collector.missing_expr();
+        let (store, source_map) = collector.store.finish();
         return (
-            Body {
-                store: collector.store.finish(),
-                params: params.into_boxed_slice(),
-                self_param,
-                body_expr,
-            },
-            BodySourceMap { self_param: source_map_self_param, store: collector.source_map },
+            Body { store, params: params.into_boxed_slice(), self_param, body_expr },
+            BodySourceMap { self_param: source_map_self_param, store: source_map },
         );
     }
 
@@ -171,14 +167,10 @@ pub(super) fn lower_body(
         },
     );
 
+    let (store, source_map) = collector.store.finish();
     (
-        Body {
-            store: collector.store.finish(),
-            params: params.into_boxed_slice(),
-            self_param,
-            body_expr,
-        },
-        BodySourceMap { self_param: source_map_self_param, store: collector.source_map },
+        Body { store, params: params.into_boxed_slice(), self_param, body_expr },
+        BodySourceMap { self_param: source_map_self_param, store: source_map },
     )
 }
 
@@ -190,7 +182,8 @@ pub(crate) fn lower_type_ref(
     let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id);
     let type_ref =
         expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator);
-    (expr_collector.store.finish(), expr_collector.source_map, type_ref)
+    let (store, source_map) = expr_collector.store.finish();
+    (store, source_map, type_ref)
 }
 
 pub(crate) fn lower_generic_params(
@@ -205,7 +198,8 @@ pub(crate) fn lower_generic_params(
     let mut collector = generics::GenericParamsCollector::new(def);
     collector.lower(&mut expr_collector, param_list, where_clause);
     let params = collector.finish();
-    (Arc::new(expr_collector.store.finish()), params, expr_collector.source_map)
+    let (store, source_map) = expr_collector.store.finish();
+    (Arc::new(store), params, source_map)
 }
 
 pub(crate) fn lower_impl(
@@ -232,7 +226,8 @@ pub(crate) fn lower_impl(
         impl_syntax.value.where_clause(),
     );
     let params = collector.finish();
-    (expr_collector.store.finish(), expr_collector.source_map, self_ty, trait_, params)
+    let (store, source_map) = expr_collector.store.finish();
+    (store, source_map, self_ty, trait_, params)
 }
 
 pub(crate) fn lower_trait(
@@ -253,7 +248,8 @@ pub(crate) fn lower_trait(
         trait_syntax.value.where_clause(),
     );
     let params = collector.finish();
-    (expr_collector.store.finish(), expr_collector.source_map, params)
+    let (store, source_map) = expr_collector.store.finish();
+    (store, source_map, params)
 }
 
 pub(crate) fn lower_trait_alias(
@@ -274,7 +270,8 @@ pub(crate) fn lower_trait_alias(
         trait_syntax.value.where_clause(),
     );
     let params = collector.finish();
-    (expr_collector.store.finish(), expr_collector.source_map, params)
+    let (store, source_map) = expr_collector.store.finish();
+    (store, source_map, params)
 }
 
 pub(crate) fn lower_type_alias(
@@ -313,7 +310,8 @@ pub(crate) fn lower_type_alias(
         .value
         .ty()
         .map(|ty| expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator));
-    (expr_collector.store.finish(), expr_collector.source_map, params, bounds, type_ref)
+    let (store, source_map) = expr_collector.store.finish();
+    (store, source_map, params, bounds, type_ref)
 }
 
 pub(crate) fn lower_function(
@@ -421,9 +419,10 @@ pub(crate) fn lower_function(
     } else {
         return_type
     };
+    let (store, source_map) = expr_collector.store.finish();
     (
-        expr_collector.store.finish(),
-        expr_collector.source_map,
+        store,
+        source_map,
         generics,
         params.into_boxed_slice(),
         return_type,
@@ -440,7 +439,6 @@ pub struct ExprCollector<'db> {
     local_def_map: &'db LocalDefMap,
     module: ModuleId,
     pub store: ExpressionStoreBuilder,
-    pub(crate) source_map: ExpressionStoreSourceMap,
 
     // state stuff
     // Prevent nested impl traits like `impl Foo<impl Bar>`.
@@ -551,7 +549,6 @@ impl ExprCollector<'_> {
             module,
             def_map,
             local_def_map,
-            source_map: ExpressionStoreSourceMap::default(),
             store: ExpressionStoreBuilder::default(),
             expander,
             current_try_block_label: None,
@@ -698,7 +695,7 @@ impl ExprCollector<'_> {
                     let id = self.collect_macro_call(mcall, macro_ptr, true, |this, expansion| {
                         this.lower_type_ref_opt(expansion, impl_trait_lower_fn)
                     });
-                    self.source_map.types_map.insert(src, id);
+                    self.store.types_map.insert(src, id);
                     return id;
                 }
                 None => TypeRef::Error,
@@ -732,8 +729,8 @@ impl ExprCollector<'_> {
     fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
         let id = self.store.types.alloc(type_ref);
         let ptr = self.expander.in_file(node);
-        self.source_map.types_map_back.insert(id, ptr);
-        self.source_map.types_map.insert(ptr, id);
+        self.store.types_map_back.insert(id, ptr);
+        self.store.types_map.insert(ptr, id);
         id
     }
 
@@ -744,8 +741,8 @@ impl ExprCollector<'_> {
     ) -> LifetimeRefId {
         let id = self.store.lifetimes.alloc(lifetime_ref);
         let ptr = self.expander.in_file(node);
-        self.source_map.lifetime_map_back.insert(id, ptr);
-        self.source_map.lifetime_map.insert(ptr, id);
+        self.store.lifetime_map_back.insert(id, ptr);
+        self.store.lifetime_map.insert(ptr, id);
         id
     }
 
@@ -1190,14 +1187,14 @@ impl ExprCollector<'_> {
             }
             ast::Expr::ContinueExpr(e) => {
                 let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
-                    self.source_map.diagnostics.push(e);
+                    self.store.diagnostics.push(e);
                     None
                 });
                 self.alloc_expr(Expr::Continue { label }, syntax_ptr)
             }
             ast::Expr::BreakExpr(e) => {
                 let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
-                    self.source_map.diagnostics.push(e);
+                    self.store.diagnostics.push(e);
                     None
                 });
                 let expr = e.expr().map(|e| self.collect_expr(e));
@@ -1207,7 +1204,7 @@ impl ExprCollector<'_> {
                 let inner = self.collect_expr_opt(e.expr());
                 // make the paren expr point to the inner expression as well for IDE resolution
                 let src = self.expander.in_file(syntax_ptr);
-                self.source_map.expr_map.insert(src, inner.into());
+                self.store.expr_map.insert(src, inner.into());
                 inner
             }
             ast::Expr::ReturnExpr(e) => {
@@ -1248,7 +1245,7 @@ impl ExprCollector<'_> {
                                 None => self.missing_expr(),
                             };
                             let src = self.expander.in_file(AstPtr::new(&field));
-                            self.source_map.field_map_back.insert(expr, src);
+                            self.store.field_map_back.insert(expr, src);
                             Some(RecordLitField { name, expr })
                         })
                         .collect();
@@ -1271,12 +1268,10 @@ impl ExprCollector<'_> {
             ast::Expr::AwaitExpr(e) => {
                 let expr = self.collect_expr_opt(e.expr());
                 if let Awaitable::No(location) = self.is_lowering_awaitable_block() {
-                    self.source_map.diagnostics.push(
-                        ExpressionStoreDiagnostics::AwaitOutsideOfAsync {
-                            node: self.expander.in_file(AstPtr::new(&e)),
-                            location: location.to_string(),
-                        },
-                    );
+                    self.store.diagnostics.push(ExpressionStoreDiagnostics::AwaitOutsideOfAsync {
+                        node: self.expander.in_file(AstPtr::new(&e)),
+                        location: location.to_string(),
+                    });
                 }
                 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
             }
@@ -1442,7 +1437,7 @@ impl ExprCollector<'_> {
                         // Make the macro-call point to its expanded expression so we can query
                         // semantics on syntax pointers to the macro
                         let src = self.expander.in_file(syntax_ptr);
-                        self.source_map.expr_map.insert(src, id.into());
+                        self.store.expr_map.insert(src, id.into());
                         id
                     }
                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -1486,7 +1481,7 @@ impl ExprCollector<'_> {
             let expr = self.collect_expr(expr);
             // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
             let id = self.store.pats.alloc(Pat::Expr(expr));
-            self.source_map.pat_map_back.insert(id, src);
+            self.store.pat_map_back.insert(id, src);
             id
         })
     }
@@ -1555,7 +1550,7 @@ impl ExprCollector<'_> {
                 let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
                     this.collect_expr_as_pat_opt(expansion)
                 });
-                self.source_map.expr_map.insert(src, id.into());
+                self.store.expr_map.insert(src, id.into());
                 id
             }
             ast::Expr::RecordExpr(e) => {
@@ -1576,7 +1571,7 @@ impl ExprCollector<'_> {
                         let pat = self.collect_expr_as_pat(field_expr);
                         let name = f.field_name()?.as_name();
                         let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
-                        self.source_map.pat_field_map_back.insert(pat, src);
+                        self.store.pat_field_map_back.insert(pat, src);
                         Some(RecordFieldPat { name, pat })
                     })
                     .collect();
@@ -1622,7 +1617,7 @@ impl ExprCollector<'_> {
                         );
                         if let Either::Left(pat) = pat {
                             let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
-                            this.source_map.pat_map_back.insert(pat, src);
+                            this.store.pat_map_back.insert(pat, src);
                         }
                         pat
                     }
@@ -1968,7 +1963,7 @@ impl ExprCollector<'_> {
                     self.module.krate(),
                     resolver,
                     &mut |ptr, call| {
-                        _ = self.source_map.expansions.insert(ptr.map(|(it, _)| it), call);
+                        _ = self.store.expansions.insert(ptr.map(|(it, _)| it), call);
                     },
                 )
             }
@@ -1978,19 +1973,17 @@ impl ExprCollector<'_> {
             Ok(res) => res,
             Err(UnresolvedMacro { path }) => {
                 if record_diagnostics {
-                    self.source_map.diagnostics.push(
-                        ExpressionStoreDiagnostics::UnresolvedMacroCall {
-                            node: self.expander.in_file(syntax_ptr),
-                            path,
-                        },
-                    );
+                    self.store.diagnostics.push(ExpressionStoreDiagnostics::UnresolvedMacroCall {
+                        node: self.expander.in_file(syntax_ptr),
+                        path,
+                    });
                 }
                 return collector(self, None);
             }
         };
         if record_diagnostics {
             if let Some(err) = res.err {
-                self.source_map
+                self.store
                     .diagnostics
                     .push(ExpressionStoreDiagnostics::MacroError { node: macro_call_ptr, err });
             }
@@ -2001,7 +1994,7 @@ impl ExprCollector<'_> {
                 // Keep collecting even with expansion errors so we can provide completions and
                 // other services in incomplete macro expressions.
                 if let Some(macro_file) = self.expander.current_file_id().macro_file() {
-                    self.source_map.expansions.insert(macro_call_ptr, macro_file);
+                    self.store.expansions.insert(macro_call_ptr, macro_file);
                 }
 
                 if record_diagnostics {
@@ -2050,7 +2043,7 @@ impl ExprCollector<'_> {
             // Make the macro-call point to its expanded expression so we can query
             // semantics on syntax pointers to the macro
             let src = self.expander.in_file(syntax_ptr);
-            self.source_map.expr_map.insert(src, tail.into());
+            self.store.expr_map.insert(src, tail.into());
         })
     }
 
@@ -2361,7 +2354,7 @@ impl ExprCollector<'_> {
                         let pat = self.collect_pat(ast_pat, binding_list);
                         let name = f.field_name()?.as_name();
                         let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
-                        self.source_map.pat_field_map_back.insert(pat, src);
+                        self.store.pat_field_map_back.insert(pat, src);
                         Some(RecordFieldPat { name, pat })
                     })
                     .collect();
@@ -2424,7 +2417,7 @@ impl ExprCollector<'_> {
                         self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
                             this.collect_pat_opt(expanded_pat, binding_list)
                         });
-                    self.source_map.pat_map.insert(src, pat.into());
+                    self.store.pat_map.insert(src, pat.into());
                     return pat;
                 }
                 None => Pat::Missing,
@@ -2515,7 +2508,7 @@ impl ExprCollector<'_> {
                             }
                         });
                     if let Some(pat) = pat.left() {
-                        self.source_map.pat_map.insert(src, pat.into());
+                        self.store.pat_map.insert(src, pat.into());
                     }
                     pat
                 }
@@ -2537,7 +2530,7 @@ impl ExprCollector<'_> {
         match enabled {
             Ok(()) => true,
             Err(cfg) => {
-                self.source_map.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode {
+                self.store.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode {
                     node: self.expander.in_file(SyntaxNodePtr::new(owner.syntax())),
                     cfg,
                     opts: self.cfg_options.clone(),
@@ -2548,7 +2541,7 @@ impl ExprCollector<'_> {
     }
 
     fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) {
-        self.source_map.binding_definitions.entry(binding_id).or_default().push(pat_id);
+        self.store.binding_definitions.entry(binding_id).or_default().push(pat_id);
     }
 
     // region: labels
@@ -2724,7 +2717,7 @@ impl ExprCollector<'_> {
                     |name, range| {
                         let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
                         if let Some(range) = range {
-                            self.source_map
+                            self.store
                                 .template_map
                                 .get_or_insert_with(Default::default)
                                 .implicit_capture_to_source
@@ -2836,7 +2829,7 @@ impl ExprCollector<'_> {
             )
         };
 
-        self.source_map
+        self.store
             .template_map
             .get_or_insert_with(Default::default)
             .format_args_to_captures
@@ -3386,8 +3379,8 @@ impl ExprCollector<'_> {
     fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
         let src = self.expander.in_file(ptr);
         let id = self.store.exprs.alloc(expr);
-        self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
-        self.source_map.expr_map.insert(src, id.into());
+        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
+        self.store.expr_map.insert(src, id.into());
         id
     }
     // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
@@ -3398,9 +3391,9 @@ impl ExprCollector<'_> {
     fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
         let src = self.expander.in_file(ptr);
         let id = self.store.exprs.alloc(expr);
-        self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
+        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
         // We intentionally don't fill this as it could overwrite a non-desugared entry
-        // self.source_map.expr_map.insert(src, id);
+        // self.store.expr_map.insert(src, id);
         id
     }
     fn missing_expr(&mut self) -> ExprId {
@@ -3423,24 +3416,24 @@ impl ExprCollector<'_> {
     fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
         let src = self.expander.in_file(ptr);
         let id = self.store.pats.alloc(pat);
-        self.source_map.expr_map.insert(src, id.into());
-        self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
+        self.store.expr_map.insert(src, id.into());
+        self.store.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
         id
     }
 
     fn alloc_expr_from_pat(&mut self, expr: Expr, ptr: PatPtr) -> ExprId {
         let src = self.expander.in_file(ptr);
         let id = self.store.exprs.alloc(expr);
-        self.source_map.pat_map.insert(src, id.into());
-        self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_right));
+        self.store.pat_map.insert(src, id.into());
+        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_right));
         id
     }
 
     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
         let src = self.expander.in_file(ptr);
         let id = self.store.pats.alloc(pat);
-        self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
-        self.source_map.pat_map.insert(src, id.into());
+        self.store.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
+        self.store.pat_map.insert(src, id.into());
         id
     }
     // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
@@ -3454,8 +3447,8 @@ impl ExprCollector<'_> {
     fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
         let src = self.expander.in_file(ptr);
         let id = self.store.labels.alloc(label);
-        self.source_map.label_map_back.insert(id, src);
-        self.source_map.label_map.insert(src, id);
+        self.store.label_map_back.insert(id, src);
+        self.store.label_map.insert(src, id);
         id
     }
     // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
index d36e5205c73..3bc4afb5c8a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
@@ -10,7 +10,7 @@ use tt::TextRange;
 
 use crate::{
     expr_store::lower::{ExprCollector, FxIndexSet},
-    hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmRegOrRegClass},
+    hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmKind, InlineAsmRegOrRegClass},
 };
 
 impl ExprCollector<'_> {
@@ -269,11 +269,20 @@ impl ExprCollector<'_> {
                     }
                 })
         };
+
+        let kind = if asm.global_asm_token().is_some() {
+            InlineAsmKind::GlobalAsm
+        } else if asm.naked_asm_token().is_some() {
+            InlineAsmKind::NakedAsm
+        } else {
+            InlineAsmKind::Asm
+        };
+
         let idx = self.alloc_expr(
-            Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }),
+            Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options, kind }),
             syntax_ptr,
         );
-        self.source_map
+        self.store
             .template_map
             .get_or_insert_with(Default::default)
             .asm_to_captures
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
index 8fd81c7b3df..f507841a91b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
@@ -23,7 +23,7 @@ fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option<Path>) {
     let mut ctx =
         ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into());
     let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator);
-    let store = ctx.store.finish();
+    let (store, _) = ctx.store.finish();
     (db, store, lowered_path)
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
index 87bcd33ed7b..f1b011333d9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
@@ -902,7 +902,7 @@ impl Printer<'_> {
                         let mut same_name = false;
                         if let Pat::Bind { id, subpat: None } = &self.store[arg.pat] {
                             if let Binding { name, mode: BindingAnnotation::Unannotated, .. } =
-                                &self.store.bindings[*id]
+                                &self.store.assert_expr_only().bindings[*id]
                             {
                                 if name.as_str() == field_name {
                                     same_name = true;
@@ -1063,7 +1063,7 @@ impl Printer<'_> {
     }
 
     fn print_binding(&mut self, id: BindingId) {
-        let Binding { name, mode, .. } = &self.store.bindings[id];
+        let Binding { name, mode, .. } = &self.store.assert_expr_only().bindings[id];
         let mode = match mode {
             BindingAnnotation::Unannotated => "",
             BindingAnnotation::Mutable => "mut ",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index 2dd0b9bdb86..1952dae9d71 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -106,7 +106,9 @@ impl ExprScopes {
         let mut scopes = ExprScopes {
             scopes: Arena::default(),
             scope_entries: Arena::default(),
-            scope_by_expr: ArenaMap::with_capacity(body.exprs.len()),
+            scope_by_expr: ArenaMap::with_capacity(
+                body.expr_only.as_ref().map_or(0, |it| it.exprs.len()),
+            ),
         };
         let mut root = scopes.root_scope();
         if let Some(self_param) = body.self_param {
@@ -179,7 +181,7 @@ impl ExprScopes {
         binding: BindingId,
         hygiene: HygieneId,
     ) {
-        let Binding { name, .. } = &store.bindings[binding];
+        let Binding { name, .. } = &store[binding];
         let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene });
         self.scopes[scope].entries =
             IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry);
@@ -251,7 +253,7 @@ fn compute_expr_scopes(
     scope: &mut ScopeId,
 ) {
     let make_label =
-        |label: &Option<LabelId>| label.map(|label| (label, store.labels[label].name.clone()));
+        |label: &Option<LabelId>| label.map(|label| (label, store[label].name.clone()));
 
     let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
         compute_expr_scopes(expr, store, scopes, scope)
@@ -534,9 +536,8 @@ fn foo() {
         };
 
         let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap();
-        let pat_src = source_map
-            .pat_syntax(*source_map.binding_definitions[resolved.binding()].first().unwrap())
-            .unwrap();
+        let pat_src =
+            source_map.pat_syntax(source_map.patterns_for_binding(resolved.binding())[0]).unwrap();
 
         let local_name = pat_src.value.syntax_node_ptr().to_node(file.syntax());
         assert_eq!(local_name.text_range(), expected_name.syntax().text_range());
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index 927e280d739..c31428be28f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -508,9 +508,9 @@ fn f() {
 }
     "#,
     );
-    assert_eq!(body.bindings.len(), 1, "should have a binding for `B`");
+    assert_eq!(body.assert_expr_only().bindings.len(), 1, "should have a binding for `B`");
     assert_eq!(
-        body.bindings[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(),
+        body[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(),
         "B",
         "should have a binding for `B`",
     );
@@ -566,6 +566,7 @@ const fn f(x: i32) -> i32 {
     );
 
     let mtch_arms = body
+        .assert_expr_only()
         .exprs
         .iter()
         .find_map(|(_, expr)| {
@@ -578,10 +579,10 @@ const fn f(x: i32) -> i32 {
         .unwrap();
 
     let MatchArm { pat, .. } = mtch_arms[1];
-    match body.pats[pat] {
+    match body[pat] {
         Pat::Range { start, end } => {
-            let hir_start = &body.exprs[start.unwrap()];
-            let hir_end = &body.exprs[end.unwrap()];
+            let hir_start = &body[start.unwrap()];
+            let hir_end = &body[end.unwrap()];
 
             assert!(matches!(hir_start, Expr::Path { .. }));
             assert!(matches!(hir_end, Expr::Path { .. }));
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index 0fc7857d978..e70cd2cd6c5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -332,6 +332,17 @@ pub struct OffsetOf {
 pub struct InlineAsm {
     pub operands: Box<[(Option<Name>, AsmOperand)]>,
     pub options: AsmOptions,
+    pub kind: InlineAsmKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum InlineAsmKind {
+    /// `asm!()`.
+    Asm,
+    /// `global_asm!()`.
+    GlobalAsm,
+    /// `naked_asm!()`.
+    NakedAsm,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index f3273667158..5ab61c89394 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -143,6 +143,8 @@ impl<'a> Ctx<'a> {
             ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(),
             ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(),
             ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
+            // FIXME: Handle `global_asm!()`.
+            ast::Item::AsmExpr(_) => return None,
         };
         let attrs = RawAttrs::new(self.db, item, self.span_map());
         self.add_attrs(mod_item.ast_id(), attrs);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 5923b3ea491..91b42bef8f7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -35,10 +35,10 @@ use a::{c, d::{e}};
             #![no_std]
             #![doc = " another file comment"]
 
-            // AstId: ExternCrate[5A82, 0]
+            // AstId: ExternCrate[070B, 0]
             pub(self) extern crate self as renamed;
 
-            // AstId: ExternCrate[7E1C, 0]
+            // AstId: ExternCrate[1EA5, 0]
             pub(in super) extern crate bli;
 
             // AstId: Use[0000, 0]
@@ -78,15 +78,15 @@ extern "C" {
             // AstId: ExternBlock[0000, 0]
             extern {
                 #[on_extern_type]
-                // AstId: TypeAlias[9FDF, 0]
+                // AstId: TypeAlias[A09C, 0]
                 pub(self) type ExType;
 
                 #[on_extern_static]
-                // AstId: Static[43C1, 0]
+                // AstId: Static[D85E, 0]
                 pub(self) static EX_STATIC = _;
 
                 #[on_extern_fn]
-                // AstId: Fn[452D, 0]
+                // AstId: Fn[B240, 0]
                 pub(self) fn ex_fn;
             }
         "#]],
@@ -124,20 +124,20 @@ enum E {
 }
         "#,
         expect![[r#"
-            // AstId: Struct[DFF3, 0]
+            // AstId: Struct[ED35, 0]
             pub(self) struct Unit;
 
             #[derive(Debug)]
-            // AstId: Struct[C7A1, 0]
+            // AstId: Struct[A47C, 0]
             pub(self) struct Struct { ... }
 
-            // AstId: Struct[DAC2, 0]
+            // AstId: Struct[C8C9, 0]
             pub(self) struct Tuple(...);
 
-            // AstId: Union[2DBB, 0]
+            // AstId: Union[2797, 0]
             pub(self) union Ize { ... }
 
-            // AstId: Enum[7FF8, 0]
+            // AstId: Enum[7D23, 0]
             pub(self) enum E { ... }
         "#]],
     );
@@ -162,18 +162,18 @@ trait Tr: SuperTrait + 'lifetime {
 }
         "#,
         expect![[r#"
-            // AstId: Static[B393, 0]
+            // AstId: Static[F7C1, 0]
             pub static ST = _;
 
-            // AstId: Const[B309, 0]
+            // AstId: Const[84BB, 0]
             pub(self) const _ = _;
 
             #[attr]
             #[inner_attr_in_fn]
-            // AstId: Fn[75E3, 0]
+            // AstId: Fn[BE8F, 0]
             pub(self) fn f;
 
-            // AstId: Trait[2998, 0]
+            // AstId: Trait[9320, 0]
             pub(self) trait Tr { ... }
         "#]],
     );
@@ -197,16 +197,16 @@ mod outline;
         expect![[r##"
             #[doc = " outer"]
             #[doc = " inner"]
-            // AstId: Module[CF93, 0]
+            // AstId: Module[03AE, 0]
             pub(self) mod inline {
                 // AstId: Use[0000, 0]
                 pub(self) use super::*;
 
-                // AstId: Fn[1B26, 0]
+                // AstId: Fn[2A78, 0]
                 pub(self) fn fn_in_module;
             }
 
-            // AstId: Module[8994, 0]
+            // AstId: Module[C08B, 0]
             pub(self) mod outline;
         "##]],
     );
@@ -225,13 +225,13 @@ pub macro m2() {}
 m!();
         "#,
         expect![[r#"
-            // AstId: MacroRules[88CE, 0]
+            // AstId: MacroRules[7E68, 0]
             macro_rules! m { ... }
 
-            // AstId: MacroDef[DC34, 0]
+            // AstId: MacroDef[1C1E, 0]
             pub macro m2 { ... }
 
-            // AstId: MacroCall[612F, 0], SyntaxContextId: ROOT2024, ExpandTo: Items
+            // AstId: MacroCall[7E68, 0], SyntaxContextId: ROOT2024, ExpandTo: Items
             m!(...);
         "#]],
     );
@@ -244,7 +244,7 @@ fn pub_self() {
 pub(self) struct S;
         "#,
         expect![[r#"
-            // AstId: Struct[42E2, 0]
+            // AstId: Struct[5024, 0]
             pub(self) struct S;
         "#]],
     )
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 293868df613..1c3af47d522 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -28,6 +28,19 @@ fn test_asm_expand() {
         r#"
 #[rustc_builtin_macro]
 macro_rules! asm {() => {}}
+#[rustc_builtin_macro]
+macro_rules! global_asm {() => {}}
+#[rustc_builtin_macro]
+macro_rules! naked_asm {() => {}}
+
+global_asm! {
+    ""
+}
+
+#[unsafe(naked)]
+extern "C" fn foo() {
+    naked_asm!("");
+}
 
 fn main() {
     let i: u64 = 3;
@@ -45,6 +58,17 @@ fn main() {
         expect![[r##"
 #[rustc_builtin_macro]
 macro_rules! asm {() => {}}
+#[rustc_builtin_macro]
+macro_rules! global_asm {() => {}}
+#[rustc_builtin_macro]
+macro_rules! naked_asm {() => {}}
+
+builtin #global_asm ("")
+
+#[unsafe(naked)]
+extern "C" fn foo() {
+    builtin #naked_asm ("");
+}
 
 fn main() {
     let i: u64 = 3;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index c6d901ec93b..c489c1f7c1d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ macro_rules! f {
     };
 }
 
-struct#0:MacroRules[8C8E, 0]@58..64#14336# MyTraitMap2#0:MacroCall[D499, 0]@31..42#ROOT2024# {#0:MacroRules[8C8E, 0]@72..73#14336#
-    map#0:MacroRules[8C8E, 0]@86..89#14336#:#0:MacroRules[8C8E, 0]@89..90#14336# #0:MacroRules[8C8E, 0]@89..90#14336#::#0:MacroRules[8C8E, 0]@91..93#14336#std#0:MacroRules[8C8E, 0]@93..96#14336#::#0:MacroRules[8C8E, 0]@96..98#14336#collections#0:MacroRules[8C8E, 0]@98..109#14336#::#0:MacroRules[8C8E, 0]@109..111#14336#HashSet#0:MacroRules[8C8E, 0]@111..118#14336#<#0:MacroRules[8C8E, 0]@118..119#14336#(#0:MacroRules[8C8E, 0]@119..120#14336#)#0:MacroRules[8C8E, 0]@120..121#14336#>#0:MacroRules[8C8E, 0]@121..122#14336#,#0:MacroRules[8C8E, 0]@122..123#14336#
-}#0:MacroRules[8C8E, 0]@132..133#14336#
+struct#0:MacroRules[BE8F, 0]@58..64#14336# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#14336#
+    map#0:MacroRules[BE8F, 0]@86..89#14336#:#0:MacroRules[BE8F, 0]@89..90#14336# #0:MacroRules[BE8F, 0]@89..90#14336#::#0:MacroRules[BE8F, 0]@91..93#14336#std#0:MacroRules[BE8F, 0]@93..96#14336#::#0:MacroRules[BE8F, 0]@96..98#14336#collections#0:MacroRules[BE8F, 0]@98..109#14336#::#0:MacroRules[BE8F, 0]@109..111#14336#HashSet#0:MacroRules[BE8F, 0]@111..118#14336#<#0:MacroRules[BE8F, 0]@118..119#14336#(#0:MacroRules[BE8F, 0]@119..120#14336#)#0:MacroRules[BE8F, 0]@120..121#14336#>#0:MacroRules[BE8F, 0]@121..122#14336#,#0:MacroRules[BE8F, 0]@122..123#14336#
+}#0:MacroRules[BE8F, 0]@132..133#14336#
 "#]],
     );
 }
@@ -75,12 +75,12 @@ macro_rules! f {
     };
 }
 
-fn#0:MacroCall[D499, 0]@30..32#ROOT2024# main#0:MacroCall[D499, 0]@33..37#ROOT2024#(#0:MacroCall[D499, 0]@37..38#ROOT2024#)#0:MacroCall[D499, 0]@38..39#ROOT2024# {#0:MacroCall[D499, 0]@40..41#ROOT2024#
-    1#0:MacroCall[D499, 0]@50..51#ROOT2024#;#0:MacroCall[D499, 0]@51..52#ROOT2024#
-    1.0#0:MacroCall[D499, 0]@61..64#ROOT2024#;#0:MacroCall[D499, 0]@64..65#ROOT2024#
-    (#0:MacroCall[D499, 0]@74..75#ROOT2024#(#0:MacroCall[D499, 0]@75..76#ROOT2024#1#0:MacroCall[D499, 0]@76..77#ROOT2024#,#0:MacroCall[D499, 0]@77..78#ROOT2024# )#0:MacroCall[D499, 0]@78..79#ROOT2024#,#0:MacroCall[D499, 0]@79..80#ROOT2024# )#0:MacroCall[D499, 0]@80..81#ROOT2024#.#0:MacroCall[D499, 0]@81..82#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#.#0:MacroCall[D499, 0]@82..85#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#;#0:MacroCall[D499, 0]@85..86#ROOT2024#
-    let#0:MacroCall[D499, 0]@95..98#ROOT2024# x#0:MacroCall[D499, 0]@99..100#ROOT2024# =#0:MacroCall[D499, 0]@101..102#ROOT2024# 1#0:MacroCall[D499, 0]@103..104#ROOT2024#;#0:MacroCall[D499, 0]@104..105#ROOT2024#
-}#0:MacroCall[D499, 0]@110..111#ROOT2024#
+fn#0:MacroCall[BE8F, 0]@30..32#ROOT2024# main#0:MacroCall[BE8F, 0]@33..37#ROOT2024#(#0:MacroCall[BE8F, 0]@37..38#ROOT2024#)#0:MacroCall[BE8F, 0]@38..39#ROOT2024# {#0:MacroCall[BE8F, 0]@40..41#ROOT2024#
+    1#0:MacroCall[BE8F, 0]@50..51#ROOT2024#;#0:MacroCall[BE8F, 0]@51..52#ROOT2024#
+    1.0#0:MacroCall[BE8F, 0]@61..64#ROOT2024#;#0:MacroCall[BE8F, 0]@64..65#ROOT2024#
+    (#0:MacroCall[BE8F, 0]@74..75#ROOT2024#(#0:MacroCall[BE8F, 0]@75..76#ROOT2024#1#0:MacroCall[BE8F, 0]@76..77#ROOT2024#,#0:MacroCall[BE8F, 0]@77..78#ROOT2024# )#0:MacroCall[BE8F, 0]@78..79#ROOT2024#,#0:MacroCall[BE8F, 0]@79..80#ROOT2024# )#0:MacroCall[BE8F, 0]@80..81#ROOT2024#.#0:MacroCall[BE8F, 0]@81..82#ROOT2024#0#0:MacroCall[BE8F, 0]@82..85#ROOT2024#.#0:MacroCall[BE8F, 0]@82..85#ROOT2024#0#0:MacroCall[BE8F, 0]@82..85#ROOT2024#;#0:MacroCall[BE8F, 0]@85..86#ROOT2024#
+    let#0:MacroCall[BE8F, 0]@95..98#ROOT2024# x#0:MacroCall[BE8F, 0]@99..100#ROOT2024# =#0:MacroCall[BE8F, 0]@101..102#ROOT2024# 1#0:MacroCall[BE8F, 0]@103..104#ROOT2024#;#0:MacroCall[BE8F, 0]@104..105#ROOT2024#
+}#0:MacroCall[BE8F, 0]@110..111#ROOT2024#
 
 
 "#]],
@@ -171,7 +171,7 @@ fn main(foo: ()) {
     }
 
     fn main(foo: ()) {
-        /* error: unresolved macro unresolved */"helloworld!"#0:Fn[B9C7, 0]@236..321#ROOT2024#;
+        /* error: unresolved macro unresolved */"helloworld!"#0:Fn[15AE, 0]@236..321#ROOT2024#;
     }
 }
 
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
 #[macro_use]
 mod foo;
 
-struct#1:MacroRules[E572, 0]@59..65#14336# Foo#0:MacroCall[BDD3, 0]@32..35#ROOT2024#(#1:MacroRules[E572, 0]@70..71#14336#u32#0:MacroCall[BDD3, 0]@41..44#ROOT2024#)#1:MacroRules[E572, 0]@74..75#14336#;#1:MacroRules[E572, 0]@75..76#14336#
+struct#1:MacroRules[DB0C, 0]@59..65#14336# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#14336#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#14336#;#1:MacroRules[DB0C, 0]@75..76#14336#
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 1c69b37f164..5e95b061399 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -20,13 +20,14 @@ use base_db::RootQueryDb;
 use expect_test::Expect;
 use hir_expand::{
     AstId, InFile, MacroCallId, MacroCallKind, MacroKind,
+    builtin::quote::quote,
     db::ExpandDatabase,
     proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind},
     span_map::SpanMapRef,
 };
-use intern::Symbol;
+use intern::{Symbol, sym};
 use itertools::Itertools;
-use span::{Edition, Span};
+use span::{Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext};
 use stdx::{format_to, format_to_acc};
 use syntax::{
     AstNode, AstPtr,
@@ -34,7 +35,9 @@ use syntax::{
     SyntaxNode, T,
     ast::{self, edit::IndentLevel},
 };
+use syntax_bridge::token_tree_to_syntax_node;
 use test_fixture::WithFixture;
+use tt::{TextRange, TextSize};
 
 use crate::{
     AdtId, Lookup, ModuleDefId,
@@ -386,3 +389,38 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
         other.type_id() == TypeId::of::<Self>()
     }
 }
+
+#[test]
+fn regression_20171() {
+    // This really isn't the appropriate place to put this test, but it's convenient with access to `quote!`.
+    let span = Span {
+        range: TextRange::empty(TextSize::new(0)),
+        anchor: SpanAnchor {
+            file_id: span::EditionedFileId::current_edition(span::FileId::from_raw(0)),
+            ast_id: ROOT_ERASED_FILE_AST_ID,
+        },
+        ctx: SyntaxContext::root(Edition::CURRENT),
+    };
+    let close_brace = tt::Punct { char: '}', spacing: tt::Spacing::Alone, span };
+    let dotdot1 = tt::Punct { char: '.', spacing: tt::Spacing::Joint, span };
+    let dotdot2 = tt::Punct { char: '.', spacing: tt::Spacing::Alone, span };
+    let dollar_crate = sym::dollar_crate;
+    let tt = quote! {
+            span => {
+        if !((matches!(
+            drive_parser(&mut parser, data, false),
+            Err(TarParserError::CorruptField {
+                field: CorruptFieldContext::PaxKvLength,
+                error: GeneralParseError::ParseInt(ParseIntError { #dotdot1 #dotdot2 })
+            })
+        #close_brace  ))) {
+        #dollar_crate::panic::panic_2021!();
+    }}
+        };
+    token_tree_to_syntax_node(
+        &tt,
+        syntax_bridge::TopEntryPoint::MacroStmts,
+        &mut |_| Edition::CURRENT,
+        Edition::CURRENT,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index d5ae6f8d885..6952a9da101 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -181,9 +181,9 @@ fn foo(&self) {
     self.0. 1;
 }
 
-fn#0:Fn[4D85, 0]@45..47#ROOT2024# foo#0:Fn[4D85, 0]@48..51#ROOT2024#(#0:Fn[4D85, 0]@51..52#ROOT2024#&#0:Fn[4D85, 0]@52..53#ROOT2024#self#0:Fn[4D85, 0]@53..57#ROOT2024# )#0:Fn[4D85, 0]@57..58#ROOT2024# {#0:Fn[4D85, 0]@59..60#ROOT2024#
-    self#0:Fn[4D85, 0]@65..69#ROOT2024# .#0:Fn[4D85, 0]@69..70#ROOT2024#0#0:Fn[4D85, 0]@70..71#ROOT2024#.#0:Fn[4D85, 0]@71..72#ROOT2024#1#0:Fn[4D85, 0]@73..74#ROOT2024#;#0:Fn[4D85, 0]@74..75#ROOT2024#
-}#0:Fn[4D85, 0]@76..77#ROOT2024#"#]],
+fn#0:Fn[8A31, 0]@45..47#ROOT2024# foo#0:Fn[8A31, 0]@48..51#ROOT2024#(#0:Fn[8A31, 0]@51..52#ROOT2024#&#0:Fn[8A31, 0]@52..53#ROOT2024#self#0:Fn[8A31, 0]@53..57#ROOT2024# )#0:Fn[8A31, 0]@57..58#ROOT2024# {#0:Fn[8A31, 0]@59..60#ROOT2024#
+    self#0:Fn[8A31, 0]@65..69#ROOT2024# .#0:Fn[8A31, 0]@69..70#ROOT2024#0#0:Fn[8A31, 0]@70..71#ROOT2024#.#0:Fn[8A31, 0]@71..72#ROOT2024#1#0:Fn[8A31, 0]@73..74#ROOT2024#;#0:Fn[8A31, 0]@74..75#ROOT2024#
+}#0:Fn[8A31, 0]@76..77#ROOT2024#"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 0837308d5b6..5030585147d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -373,19 +373,14 @@ pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap {
     crate_local_def_map(db, crate_id).def_map(db)
 }
 
-#[allow(unused_lifetimes)]
-mod __ {
-    use super::*;
-    #[salsa_macros::tracked]
-    pub(crate) struct DefMapPair<'db> {
-        #[tracked]
-        #[returns(ref)]
-        pub(crate) def_map: DefMap,
-        #[returns(ref)]
-        pub(crate) local: LocalDefMap,
-    }
+#[salsa_macros::tracked]
+pub(crate) struct DefMapPair<'db> {
+    #[tracked]
+    #[returns(ref)]
+    pub(crate) def_map: DefMap,
+    #[returns(ref)]
+    pub(crate) local: LocalDefMap,
 }
-pub(crate) use __::DefMapPair;
 
 #[salsa_macros::tracked(returns(ref))]
 pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 6f321980af4..316ad5dae69 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -1052,17 +1052,6 @@ impl<'db> Scope<'db> {
     }
 }
 
-pub fn resolver_for_expr(
-    db: &dyn DefDatabase,
-    owner: DefWithBodyId,
-    expr_id: ExprId,
-) -> Resolver<'_> {
-    let r = owner.resolver(db);
-    let scopes = db.expr_scopes(owner);
-    let scope_id = scopes.scope_for(expr_id);
-    resolver_for_scope_(db, scopes, scope_id, r, owner)
-}
-
 pub fn resolver_for_scope(
     db: &dyn DefDatabase,
     owner: DefWithBodyId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
index 1958eb6c6a1..92e610b36ac 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
@@ -779,14 +779,10 @@ impl VariantFields {
                 Arc::new(VariantFields { fields, store: Arc::new(store), shape }),
                 Arc::new(source_map),
             ),
-            None => (
-                Arc::new(VariantFields {
-                    fields: Arena::default(),
-                    store: ExpressionStore::empty_singleton(),
-                    shape,
-                }),
-                ExpressionStoreSourceMap::empty_singleton(),
-            ),
+            None => {
+                let (store, source_map) = ExpressionStore::empty_singleton();
+                (Arc::new(VariantFields { fields: Arena::default(), store, shape }), source_map)
+            }
         }
     }
 
@@ -878,7 +874,7 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
                 idx += 1;
             }
             Err(cfg) => {
-                col.source_map.diagnostics.push(
+                col.store.diagnostics.push(
                     crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
                         node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())),
                         cfg,
@@ -891,9 +887,9 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
     if !has_fields {
         return None;
     }
-    let store = col.store.finish();
+    let (store, source_map) = col.store.finish();
     arena.shrink_to_fit();
-    Some((arena, store, col.source_map))
+    Some((arena, store, source_map))
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -980,7 +976,7 @@ impl EnumVariants {
             if !matches!(variant.shape, FieldsShape::Unit) {
                 let body = db.body(v.into());
                 // A variant with explicit discriminant
-                if body.exprs[body.body_expr] != crate::hir::Expr::Missing {
+                if !matches!(body[body.body_expr], crate::hir::Expr::Missing) {
                     return false;
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index 800b40a9e7e..60fbc660652 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -125,8 +125,8 @@ register_builtin! {
     (assert, Assert) => assert_expand,
     (stringify, Stringify) => stringify_expand,
     (asm, Asm) => asm_expand,
-    (global_asm, GlobalAsm) => asm_expand,
-    (naked_asm, NakedAsm) => asm_expand,
+    (global_asm, GlobalAsm) => global_asm_expand,
+    (naked_asm, NakedAsm) => naked_asm_expand,
     (cfg, Cfg) => cfg_expand,
     (core_panic, CorePanic) => panic_expand,
     (std_panic, StdPanic) => panic_expand,
@@ -325,6 +325,36 @@ fn asm_expand(
     ExpandResult::ok(expanded)
 }
 
+fn global_asm_expand(
+    _db: &dyn ExpandDatabase,
+    _id: MacroCallId,
+    tt: &tt::TopSubtree,
+    span: Span,
+) -> ExpandResult<tt::TopSubtree> {
+    let mut tt = tt.clone();
+    tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
+    let pound = mk_pound(span);
+    let expanded = quote! {span =>
+        builtin #pound global_asm #tt
+    };
+    ExpandResult::ok(expanded)
+}
+
+fn naked_asm_expand(
+    _db: &dyn ExpandDatabase,
+    _id: MacroCallId,
+    tt: &tt::TopSubtree,
+    span: Span,
+) -> ExpandResult<tt::TopSubtree> {
+    let mut tt = tt.clone();
+    tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
+    let pound = mk_pound(span);
+    let expanded = quote! {span =>
+        builtin #pound naked_asm #tt
+    };
+    ExpandResult::ok(expanded)
+}
+
 fn cfg_expand(
     db: &dyn ExpandDatabase,
     id: MacroCallId,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
index d5874f829ba..70c38d4d7c7 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
@@ -129,7 +129,7 @@ macro_rules! quote {
         }
     }
 }
-pub(super) use quote;
+pub use quote;
 
 pub trait ToTokenTree {
     fn to_tokens(self, span: Span, builder: &mut TopSubtreeBuilder);
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 679f61112ad..217d991d110 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -179,10 +179,9 @@ impl Name {
         self.symbol.as_str()
     }
 
-    #[inline]
     pub fn display<'a>(
         &'a self,
-        db: &dyn salsa::Database,
+        db: &dyn crate::db::ExpandDatabase,
         edition: Edition,
     ) -> impl fmt::Display + 'a {
         _ = db;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 24530a5f67c..14b9cd203f6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -281,7 +281,7 @@ pub(crate) fn const_eval_discriminant_variant(
     let def = variant_id.into();
     let body = db.body(def);
     let loc = variant_id.lookup(db);
-    if body.exprs[body.body_expr] == Expr::Missing {
+    if matches!(body[body.body_expr], Expr::Missing) {
         let prev_idx = loc.index.checked_sub(1);
         let value = match prev_idx {
             Some(prev_idx) => {
@@ -334,7 +334,7 @@ pub(crate) fn eval_to_const(
         // Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic.
         return unknown_const(infer[expr].clone());
     }
-    if let Expr::Path(p) = &ctx.body.exprs[expr] {
+    if let Expr::Path(p) = &ctx.body[expr] {
         let resolver = &ctx.resolver;
         if let Some(c) =
             path_to_const(db, resolver, p, mode, || ctx.generics(), debruijn, infer[expr].clone())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 5d3be07f3db..b3d46845c44 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -273,8 +273,9 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     #[salsa::invoke(crate::variance::variances_of)]
     #[salsa::cycle(
-        cycle_fn = crate::variance::variances_of_cycle_fn,
-        cycle_initial = crate::variance::variances_of_cycle_initial,
+        // cycle_fn = crate::variance::variances_of_cycle_fn,
+        // cycle_initial = crate::variance::variances_of_cycle_initial,
+        cycle_result = crate::variance::variances_of_cycle_initial,
     )]
     fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 9c0f8f40080..40fe3073cf2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -226,11 +226,10 @@ impl<'a> DeclValidator<'a> {
         let body = self.db.body(func.into());
         let edition = self.edition(func);
         let mut pats_replacements = body
-            .pats
-            .iter()
+            .pats()
             .filter_map(|(pat_id, pat)| match pat {
                 Pat::Bind { id, .. } => {
-                    let bind_name = &body.bindings[*id].name;
+                    let bind_name = &body[*id].name;
                     let mut suggested_text = to_lower_snake_case(bind_name.as_str())?;
                     if is_raw_identifier(&suggested_text, edition) {
                         suggested_text.insert_str(0, "r#");
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 5d56957be6d..5ae6bf6dffd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -101,7 +101,7 @@ impl ExprValidator {
             self.check_for_trailing_return(body.body_expr, &body);
         }
 
-        for (id, expr) in body.exprs.iter() {
+        for (id, expr) in body.exprs() {
             if let Some((variant, missed_fields, true)) =
                 record_literal_missing_fields(db, &self.infer, id, expr)
             {
@@ -132,7 +132,7 @@ impl ExprValidator {
             }
         }
 
-        for (id, pat) in body.pats.iter() {
+        for (id, pat) in body.pats() {
             if let Some((variant, missed_fields, true)) =
                 record_pattern_missing_fields(db, &self.infer, id, pat)
             {
@@ -389,7 +389,7 @@ impl ExprValidator {
         if !self.validate_lints {
             return;
         }
-        match &body.exprs[body_expr] {
+        match &body[body_expr] {
             Expr::Block { statements, tail, .. } => {
                 let last_stmt = tail.or_else(|| match statements.last()? {
                     Statement::Expr { expr, .. } => Some(*expr),
@@ -428,7 +428,7 @@ impl ExprValidator {
             if else_branch.is_none() {
                 return;
             }
-            if let Expr::Block { statements, tail, .. } = &self.body.exprs[*then_branch] {
+            if let Expr::Block { statements, tail, .. } = &self.body[*then_branch] {
                 let last_then_expr = tail.or_else(|| match statements.last()? {
                     Statement::Expr { expr, .. } => Some(*expr),
                     _ => None,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index c3ab5aff3db..ca132fbdc45 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -150,7 +150,7 @@ impl<'a> PatCtxt<'a> {
             hir_def::hir::Pat::Bind { id, subpat, .. } => {
                 let bm = self.infer.binding_modes[pat];
                 ty = &self.infer[id];
-                let name = &self.body.bindings[id].name;
+                let name = &self.body[id].name;
                 match (bm, ty.kind(Interner)) {
                     (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty,
                     (BindingMode::Ref(_), _) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 20cf3c78115..f6ad3c7aae2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -7,7 +7,7 @@ use either::Either;
 use hir_def::{
     AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
     expr_store::{Body, path::Path},
-    hir::{AsmOperand, Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
+    hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp},
     resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
     signatures::StaticFlags,
     type_ref::Rawness,
@@ -217,7 +217,7 @@ impl<'db> UnsafeVisitor<'db> {
     }
 
     fn walk_pat(&mut self, current: PatId) {
-        let pat = &self.body.pats[current];
+        let pat = &self.body[current];
 
         if self.inside_union_destructure {
             match pat {
@@ -264,7 +264,7 @@ impl<'db> UnsafeVisitor<'db> {
     }
 
     fn walk_expr(&mut self, current: ExprId) {
-        let expr = &self.body.exprs[current];
+        let expr = &self.body[current];
         let inside_assignment = mem::replace(&mut self.inside_assignment, false);
         match expr {
             &Expr::Call { callee, .. } => {
@@ -284,7 +284,7 @@ impl<'db> UnsafeVisitor<'db> {
                 self.resolver.reset_to_guard(guard);
             }
             Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
-                match self.body.exprs[*expr] {
+                match self.body[*expr] {
                     // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
                     // see https://github.com/rust-lang/rust/pull/125834.
                     Expr::Path(_) => return,
@@ -315,7 +315,12 @@ impl<'db> UnsafeVisitor<'db> {
                 self.inside_assignment = old_inside_assignment;
             }
             Expr::InlineAsm(asm) => {
-                self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
+                if asm.kind == InlineAsmKind::Asm {
+                    // `naked_asm!()` requires `unsafe` on the attribute (`#[unsafe(naked)]`),
+                    // and `global_asm!()` doesn't require it at all.
+                    self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
+                }
+
                 asm.operands.iter().for_each(|(_, op)| match op {
                     AsmOperand::In { expr, .. }
                     | AsmOperand::Out { expr: Some(expr), .. }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 810fe76f231..b3760e3a382 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -795,6 +795,14 @@ fn render_const_scalar(
                 let Some(bytes) = memory_map.get(addr, size_one * count) else {
                     return f.write_str("<ref-data-not-available>");
                 };
+                let expected_len = count * size_one;
+                if bytes.len() < expected_len {
+                    never!(
+                        "Memory map size is too small. Expected {expected_len}, got {}",
+                        bytes.len(),
+                    );
+                    return f.write_str("<layout-error>");
+                }
                 f.write_str("&[")?;
                 let mut first = true;
                 for i in 0..count {
@@ -2328,6 +2336,7 @@ impl HirDisplayWithExpressionStore for TypeBound {
                 store[*path].hir_fmt(f, store)
             }
             TypeBound::Use(args) => {
+                write!(f, "use<")?;
                 let edition = f.edition();
                 let last = args.len().saturating_sub(1);
                 for (idx, arg) in args.iter().enumerate() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index d2eaf212365..3f7eba9dd18 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -273,7 +273,7 @@ impl InferenceContext<'_> {
     fn pat_bound_mutability(&self, pat: PatId) -> Mutability {
         let mut r = Mutability::Not;
         self.body.walk_bindings_in_pat(pat, |b| {
-            if self.body.bindings[b].mode == BindingAnnotation::RefMut {
+            if self.body[b].mode == BindingAnnotation::RefMut {
                 r = Mutability::Mut;
             }
         });
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 99d3b5c7a84..18288b718f7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -459,7 +459,7 @@ impl InferenceContext<'_> {
         expected: &Ty,
         decl: Option<DeclContext>,
     ) -> Ty {
-        let Binding { mode, .. } = self.body.bindings[binding];
+        let Binding { mode, .. } = self.body[binding];
         let mode = if mode == BindingAnnotation::Unannotated {
             default_bm
         } else {
@@ -639,7 +639,7 @@ impl InferenceContext<'_> {
 pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
     let mut res = false;
     body.walk_pats(pat_id, &mut |pat| {
-        res |= matches!(body[pat], Pat::Bind { id, .. } if body.bindings[id].mode == BindingAnnotation::Ref);
+        res |= matches!(body[pat], Pat::Bind { id, .. } if body[id].mode == BindingAnnotation::Ref);
     });
     res
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
index 88c33ecccad..82d0ed4f194 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs
@@ -2,7 +2,7 @@
 
 use base_db::Crate;
 use hir_def::layout::TargetDataLayout;
-use rustc_abi::{AlignFromBytesError, TargetDataLayoutErrors, AddressSpace};
+use rustc_abi::{AddressSpace, AlignFromBytesError, TargetDataLayoutErrors};
 use triomphe::Arc;
 
 use crate::db::HirDatabase;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index cc7d74f4fb0..b3bc226ec93 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -119,8 +119,7 @@ fn eval_expr(
         .unwrap();
     let hir_body = db.body(function_id.into());
     let b = hir_body
-        .bindings
-        .iter()
+        .bindings()
         .find(|x| x.1.name.display_no_db(file_id.edition(&db)).to_smolstr() == "goal")
         .unwrap()
         .0;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
index 06686b6a164..5c06234fa07 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
@@ -1018,8 +1018,12 @@ fn check_generic_args_len(
     }
 
     let lifetime_args_len = def_generics.len_lifetimes_self();
-    if provided_lifetimes_count == 0 && lifetime_args_len > 0 && !lowering_assoc_type_generics {
-        // In generic associated types, we never allow inferring the lifetimes.
+    if provided_lifetimes_count == 0
+        && lifetime_args_len > 0
+        && (!lowering_assoc_type_generics || infer_args)
+    {
+        // In generic associated types, we never allow inferring the lifetimes, but only in type context, that is
+        // when `infer_args == false`. In expression/pattern context we always allow inferring them, even for GATs.
         match lifetime_elision {
             &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => {
                 ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index bf80ed7967a..482b420279c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -1212,10 +1212,9 @@ impl MirSpan {
         match *self {
             MirSpan::ExprId(expr) => matches!(body[expr], Expr::Ref { .. }),
             // FIXME: Figure out if this is correct wrt. match ergonomics.
-            MirSpan::BindingId(binding) => matches!(
-                body.bindings[binding].mode,
-                BindingAnnotation::Ref | BindingAnnotation::RefMut
-            ),
+            MirSpan::BindingId(binding) => {
+                matches!(body[binding].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)
+            }
             MirSpan::PatId(_) | MirSpan::SelfParam | MirSpan::Unknown => false,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 55fada14363..9a97bd6dbe2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -31,8 +31,8 @@ use syntax::{SyntaxNodePtr, TextRange};
 use triomphe::Arc;
 
 use crate::{
-    CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner,
-    MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
+    AliasTy, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId,
+    Interner, MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
     consteval::{ConstEvalError, intern_const_scalar, try_const_usize},
     db::{HirDatabase, InternedClosure},
     display::{ClosureStyle, DisplayTarget, HirDisplay},
@@ -2195,7 +2195,7 @@ impl Evaluator<'_> {
                         }
                     }
                 }
-                chalk_ir::TyKind::Array(inner, len) => {
+                TyKind::Array(inner, len) => {
                     let len = match try_const_usize(this.db, len) {
                         Some(it) => it as usize,
                         None => not_supported!("non evaluatable array len in patching addresses"),
@@ -2213,7 +2213,7 @@ impl Evaluator<'_> {
                         )?;
                     }
                 }
-                chalk_ir::TyKind::Tuple(_, subst) => {
+                TyKind::Tuple(_, subst) => {
                     let layout = this.layout(ty)?;
                     for (id, ty) in subst.iter(Interner).enumerate() {
                         let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
@@ -2229,7 +2229,7 @@ impl Evaluator<'_> {
                         )?;
                     }
                 }
-                chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
+                TyKind::Adt(adt, subst) => match adt.0 {
                     AdtId::StructId(s) => {
                         let data = s.fields(this.db);
                         let layout = this.layout(ty)?;
@@ -2280,6 +2280,10 @@ impl Evaluator<'_> {
                     }
                     AdtId::UnionId(_) => (),
                 },
+                TyKind::Alias(AliasTy::Projection(proj)) => {
+                    let ty = this.db.normalize_projection(proj.clone(), this.trait_env.clone());
+                    rec(this, bytes, &ty, locals, mm, stack_depth_limit - 1)?;
+                }
                 _ => (),
             }
             Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 845d6b8eae1..07d81472729 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -321,7 +321,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         current: BasicBlockId,
     ) -> Result<Option<(Operand, BasicBlockId)>> {
         if !self.has_adjustments(expr_id) {
-            if let Expr::Literal(l) = &self.body.exprs[expr_id] {
+            if let Expr::Literal(l) = &self.body[expr_id] {
                 let ty = self.expr_ty_without_adjust(expr_id);
                 return Ok(Some((self.lower_literal_to_operand(ty, l)?, current)));
             }
@@ -411,7 +411,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         place: Place,
         mut current: BasicBlockId,
     ) -> Result<Option<BasicBlockId>> {
-        match &self.body.exprs[expr_id] {
+        match &self.body[expr_id] {
             Expr::OffsetOf(_) => {
                 not_supported!("builtin#offset_of")
             }
@@ -1374,7 +1374,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
     }
 
     fn lower_literal_or_const_to_operand(&mut self, ty: Ty, loc: &ExprId) -> Result<Operand> {
-        match &self.body.exprs[*loc] {
+        match &self.body[*loc] {
             Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
             Expr::Path(c) => {
                 let owner = self.owner;
@@ -1850,7 +1850,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             self.drop_scopes.last_mut().unwrap().locals.push(local_id);
             if let Pat::Bind { id, subpat: None } = self.body[it] {
                 if matches!(
-                    self.body.bindings[id].mode,
+                    self.body[id].mode,
                     BindingAnnotation::Unannotated | BindingAnnotation::Mutable
                 ) {
                     self.result.binding_locals.insert(id, local_id);
@@ -1859,7 +1859,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             local_id
         }));
         // and then rest of bindings
-        for (id, _) in self.body.bindings.iter() {
+        for (id, _) in self.body.bindings() {
             if !pick_binding(id) {
                 continue;
             }
@@ -2126,7 +2126,7 @@ pub fn mir_body_for_closure_query(
         .result
         .binding_locals
         .into_iter()
-        .filter(|it| ctx.body.binding_owners.get(&it.0).copied() == Some(expr))
+        .filter(|it| ctx.body.binding_owner(it.0) == Some(expr))
         .collect();
     if let Some(err) = err {
         return Err(MirLowerError::UnresolvedUpvar(err));
@@ -2191,7 +2191,7 @@ pub fn lower_to_mir(
     // 0 is return local
     ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr) });
     let binding_picker = |b: BindingId| {
-        let owner = ctx.body.binding_owners.get(&b).copied();
+        let owner = ctx.body.binding_owner(b);
         if root_expr == body.body_expr { owner.is_none() } else { owner == Some(root_expr) }
     };
     // 1 to param_len is for params
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index e7bffead931..e074c2d558e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -133,7 +133,7 @@ impl MirLowerCtx<'_> {
             }
             this.lower_expr_to_some_place_without_adjust(expr_id, current)
         };
-        match &self.body.exprs[expr_id] {
+        match &self.body[expr_id] {
             Expr::Path(p) => {
                 let resolver_guard =
                     self.resolver.update_to_inner_scope(self.db, self.owner, expr_id);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 61c0685c48a..3325226b1d3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -130,7 +130,7 @@ impl MirLowerCtx<'_> {
                 .collect::<Vec<_>>()
                 .into(),
         );
-        Ok(match &self.body.pats[pattern] {
+        Ok(match &self.body[pattern] {
             Pat::Missing => return Err(MirLowerError::IncompletePattern),
             Pat::Wild => (current, current_else),
             Pat::Tuple { args, ellipsis } => {
@@ -436,7 +436,7 @@ impl MirLowerCtx<'_> {
                     (next, Some(else_target))
                 }
             },
-            Pat::Lit(l) => match &self.body.exprs[*l] {
+            Pat::Lit(l) => match &self.body[*l] {
                 Expr::Literal(l) => {
                     if mode == MatchingMode::Check {
                         let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 78a69cf4509..aad54f88438 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -219,7 +219,7 @@ impl<'a> MirPrettyCtx<'a> {
 
     fn local_name(&self, local: LocalId) -> LocalName {
         match self.local_to_binding.get(local) {
-            Some(b) => LocalName::Binding(self.hir_body.bindings[*b].name.clone(), local),
+            Some(b) => LocalName::Binding(self.hir_body[*b].name.clone(), local),
             None => LocalName::Unknown(local),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index 79754bc8a09..9605a0b4124 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -168,7 +168,7 @@ fn check_impl(
         let inference_result = db.infer(def);
 
         for (pat, mut ty) in inference_result.type_of_pat.iter() {
-            if let Pat::Bind { id, .. } = body.pats[pat] {
+            if let Pat::Bind { id, .. } = body[pat] {
                 ty = &inference_result.type_of_binding[id];
             }
             let node = match pat_node(&body_source_map, pat, &db) {
@@ -316,7 +316,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
         }
 
         for (pat, mut ty) in inference_result.type_of_pat.iter() {
-            if let Pat::Bind { id, .. } = body.pats[pat] {
+            if let Pat::Bind { id, .. } = body[pat] {
                 ty = &inference_result.type_of_binding[id];
             }
             let node = match body_source_map.pat_syntax(pat) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index 87d9df611bd..08a215fecf6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -54,14 +54,14 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar
     variances.is_empty().not().then(|| Arc::from_iter(variances))
 }
 
-pub(crate) fn variances_of_cycle_fn(
-    _db: &dyn HirDatabase,
-    _result: &Option<Arc<[Variance]>>,
-    _count: u32,
-    _def: GenericDefId,
-) -> salsa::CycleRecoveryAction<Option<Arc<[Variance]>>> {
-    salsa::CycleRecoveryAction::Iterate
-}
+// pub(crate) fn variances_of_cycle_fn(
+//     _db: &dyn HirDatabase,
+//     _result: &Option<Arc<[Variance]>>,
+//     _count: u32,
+//     _def: GenericDefId,
+// ) -> salsa::CycleRecoveryAction<Option<Arc<[Variance]>>> {
+//     salsa::CycleRecoveryAction::Iterate
+// }
 
 pub(crate) fn variances_of_cycle_initial(
     db: &dyn HirDatabase,
@@ -965,7 +965,7 @@ struct S3<T>(S<T, T>);
 struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V);
 "#,
             expect![[r#"
-                FixedPoint[T: covariant, U: covariant, V: covariant]
+                FixedPoint[T: bivariant, U: bivariant, V: bivariant]
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 5c6f622e6c3..1b2b76999f7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -2036,7 +2036,7 @@ impl DefWithBody {
                     )
                 }
                 let mol = &borrowck_result.mutability_of_locals;
-                for (binding_id, binding_data) in body.bindings.iter() {
+                for (binding_id, binding_data) in body.bindings() {
                     if binding_data.problems.is_some() {
                         // We should report specific diagnostics for these problems, not `need-mut` and `unused-mut`.
                         continue;
@@ -3222,7 +3222,8 @@ impl Macro {
         }
     }
 
-    pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool {
+    /// Is this `asm!()`, or a variant of it (e.g. `global_asm!()`)?
+    pub fn is_asm_like(&self, db: &dyn HirDatabase) -> bool {
         match self.id {
             MacroId::Macro2Id(it) => {
                 matches!(it.lookup(db).expander, MacroExpander::BuiltIn(m) if m.is_asm())
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 247bb693983..adba59236a4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -677,8 +677,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> {
         let body = self.db.body(to_be_renamed.parent);
         let resolver = to_be_renamed.parent.resolver(self.db);
-        let starting_expr =
-            body.binding_owners.get(&to_be_renamed.binding_id).copied().unwrap_or(body.body_expr);
+        let starting_expr = body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.body_expr);
         let mut visitor = RenameConflictsVisitor {
             body: &body,
             conflicts: FxHashSet::default(),
@@ -1776,7 +1775,7 @@ impl<'db> SemanticsImpl<'db> {
 
     pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
         let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
-        if mac.is_asm_or_global_asm(self.db) {
+        if mac.is_asm_like(self.db) {
             return true;
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 0662bfddcf8..ecc6e5f3d03 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -242,11 +242,7 @@ impl<'db> SourceAnalyzer<'db> {
 
     fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> {
         let pat_id = self.pat_id(&pat.clone().into())?;
-        if let Pat::Bind { id, .. } = self.store()?.pats[pat_id.as_pat()?] {
-            Some(id)
-        } else {
-            None
-        }
+        if let Pat::Bind { id, .. } = self.store()?[pat_id.as_pat()?] { Some(id) } else { None }
     }
 
     pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]> {
@@ -995,7 +991,7 @@ impl<'db> SourceAnalyzer<'db> {
         let parent_hir_path = path
             .parent_path()
             .and_then(|p| collector.lower_path(p, &mut ExprCollector::impl_trait_error_allocator));
-        let store = collector.store.finish();
+        let (store, _) = collector.store.finish();
 
         // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
         // trying to resolve foo::bar.
@@ -1204,7 +1200,7 @@ impl<'db> SourceAnalyzer<'db> {
         let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
         let hir_path =
             collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
-        let store = collector.store.finish();
+        let (store, _) = collector.store.finish();
         Some(resolve_hir_path_(
             db,
             &self.resolver,
@@ -1439,9 +1435,11 @@ fn scope_for(
 ) -> Option<ScopeId> {
     node.ancestors_with_macros(db)
         .take_while(|it| {
-            !ast::Item::can_cast(it.kind())
-                || ast::MacroCall::can_cast(it.kind())
-                || ast::Use::can_cast(it.kind())
+            let kind = it.kind();
+            !ast::Item::can_cast(kind)
+                || ast::MacroCall::can_cast(kind)
+                || ast::Use::can_cast(kind)
+                || ast::AsmExpr::can_cast(kind)
         })
         .filter_map(|it| it.map(ast::Expr::cast).transpose())
         .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index 756650891d4..dca10193e29 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -125,6 +125,13 @@ impl<'a> SymbolCollector<'a> {
                 }
                 ModuleDefId::AdtId(AdtId::EnumId(id)) => {
                     this.push_decl(id, name, false, None);
+                    let enum_name = this.db.enum_signature(id).name.as_str().to_smolstr();
+                    this.with_container_name(Some(enum_name), |this| {
+                        let variants = id.enum_variants(this.db);
+                        for (variant_id, variant_name, _) in &variants.variants {
+                            this.push_decl(*variant_id, variant_name, true, None);
+                        }
+                    });
                 }
                 ModuleDefId::AdtId(AdtId::UnionId(id)) => {
                     this.push_decl(id, name, false, None);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
index efcbcef00e9..9126e869b9a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
@@ -1,8 +1,8 @@
 use ide_db::defs::{Definition, NameRefClass};
 use syntax::{
     AstNode, SyntaxNode,
-    ast::{self, HasName, Name},
-    ted,
+    ast::{self, HasName, Name, syntax_factory::SyntaxFactory},
+    syntax_editor::SyntaxEditor,
 };
 
 use crate::{
@@ -121,34 +121,36 @@ fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Opti
 
 // Rename `extracted` with `binding` in `pat`.
 fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> SyntaxNode {
-    let syntax = pat.syntax().clone_for_update();
+    let syntax = pat.syntax().clone_subtree();
+    let mut editor = SyntaxEditor::new(syntax.clone());
+    let make = SyntaxFactory::with_mappings();
     let extracted = extracted
         .iter()
-        .map(|e| syntax.covering_element(e.syntax().text_range()))
+        .map(|e| e.syntax().text_range() - pat.syntax().text_range().start())
+        .map(|r| syntax.covering_element(r))
         .collect::<Vec<_>>();
     for extracted_syntax in extracted {
         // If `extracted` variable is a record field, we should rename it to `binding`,
         // otherwise we just need to replace `extracted` with `binding`.
-
         if let Some(record_pat_field) =
             extracted_syntax.ancestors().find_map(ast::RecordPatField::cast)
         {
             if let Some(name_ref) = record_pat_field.field_name() {
-                ted::replace(
+                editor.replace(
                     record_pat_field.syntax(),
-                    ast::make::record_pat_field(
-                        ast::make::name_ref(&name_ref.text()),
-                        binding.clone(),
+                    make.record_pat_field(
+                        make.name_ref(&name_ref.text()),
+                        binding.clone_for_update(),
                     )
-                    .syntax()
-                    .clone_for_update(),
+                    .syntax(),
                 );
             }
         } else {
-            ted::replace(extracted_syntax, binding.clone().syntax().clone_for_update());
+            editor.replace(extracted_syntax, binding.syntax().clone_for_update());
         }
     }
-    syntax
+    editor.add_mappings(make.finish_with_mappings());
+    editor.finish().new_root().clone()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 32c4ae2e869..8d27574eb2c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -4,7 +4,8 @@ use itertools::Itertools;
 use syntax::{
     SyntaxKind,
     ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility},
-    match_ast, ted,
+    match_ast,
+    syntax_editor::{Position, SyntaxEditor},
 };
 
 use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder};
@@ -97,11 +98,14 @@ fn edit_struct_def(
     // Note that we don't need to consider macro files in this function because this is
     // currently not triggered for struct definitions inside macro calls.
     let tuple_fields = record_fields.fields().filter_map(|f| {
-        let field = ast::make::tuple_field(f.visibility(), f.ty()?).clone_for_update();
-        ted::insert_all(
-            ted::Position::first_child_of(field.syntax()),
+        let field = ast::make::tuple_field(f.visibility(), f.ty()?);
+        let mut editor = SyntaxEditor::new(field.syntax().clone());
+        editor.insert_all(
+            Position::first_child_of(field.syntax()),
             f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
         );
+        let field_syntax = editor.finish().new_root().clone();
+        let field = ast::TupleField::cast(field_syntax)?;
         Some(field)
     });
     let tuple_fields = ast::make::tuple_field_list(tuple_fields);
@@ -1086,8 +1090,7 @@ pub struct $0Foo {
 }
 "#,
             r#"
-pub struct Foo(#[my_custom_attr]
-u32);
+pub struct Foo(#[my_custom_attr]u32);
 "#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
index 79a78ab3698..47233fb399d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
@@ -2,7 +2,7 @@ use ide_db::famous_defs::FamousDefs;
 use stdx::format_to;
 use syntax::{
     AstNode,
-    ast::{self, HasGenericParams, HasName, Impl, make},
+    ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl, make},
 };
 
 use crate::{
@@ -88,20 +88,19 @@ fn generate_trait_impl_text_from_impl(
     let generic_params = impl_.generic_param_list().map(|generic_params| {
         let lifetime_params =
             generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
-        let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
+        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
             // remove defaults since they can't be specified in impls
-            match param {
+            let param = match param {
                 ast::TypeOrConstParam::Type(param) => {
-                    let param = param.clone_for_update();
-                    param.remove_default();
+                    let param = make::type_param(param.name()?, param.type_bound_list());
                     ast::GenericParam::TypeParam(param)
                 }
                 ast::TypeOrConstParam::Const(param) => {
-                    let param = param.clone_for_update();
-                    param.remove_default();
+                    let param = make::const_param(param.name()?, param.ty()?);
                     ast::GenericParam::ConstParam(param)
                 }
-            }
+            };
+            Some(param)
         });
 
         make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index c7e5e41aac4..20ee9253d37 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -294,7 +294,7 @@ fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldI
     let self_expr = make::ext::expr_self();
     let lhs = make::expr_field(self_expr, field_name);
     let rhs = make::expr_path(make::ext::ident_path(field_name));
-    let assign_stmt = make::expr_stmt(make::expr_assignment(lhs, rhs));
+    let assign_stmt = make::expr_stmt(make::expr_assignment(lhs, rhs).into());
     let body = make::block_expr([assign_stmt.into()], None);
 
     // Make the setter fn
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index 2862e6d5afb..14601ca0207 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -1,14 +1,14 @@
 use syntax::{
     ast::{self, AstNode, HasName, edit_in_place::Indent, make},
-    ted,
+    syntax_editor::{Position, SyntaxEditor},
 };
 
 use crate::{AssistContext, AssistId, Assists, utils};
 
-fn insert_impl(impl_: ast::Impl, nominal: &ast::Adt) {
+fn insert_impl(editor: &mut SyntaxEditor, impl_: &ast::Impl, nominal: &ast::Adt) {
     let indent = nominal.indent_level();
-    ted::insert_all_raw(
-        ted::Position::after(nominal.syntax()),
+    editor.insert_all(
+        Position::after(nominal.syntax()),
         vec![
             // Add a blank line after the ADT, and indentation for the impl to match the ADT
             make::tokens::whitespace(&format!("\n\n{indent}")).into(),
@@ -51,14 +51,17 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
             // Generate the impl
             let impl_ = utils::generate_impl(&nominal);
 
+            let mut editor = edit.make_editor(nominal.syntax());
             // Add a tabstop after the left curly brace
             if let Some(cap) = ctx.config.snippet_cap {
                 if let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) {
-                    edit.add_tabstop_after_token(cap, l_curly);
+                    let tabstop = edit.make_tabstop_after(cap);
+                    editor.add_annotation(l_curly, tabstop);
                 }
             }
 
-            insert_impl(impl_, &edit.make_mut(nominal));
+            insert_impl(&mut editor, &impl_, &nominal);
+            edit.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
@@ -97,18 +100,22 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             // Generate the impl
             let impl_ = utils::generate_trait_impl_intransitive(&nominal, make::ty_placeholder());
 
+            let mut editor = edit.make_editor(nominal.syntax());
             // Make the trait type a placeholder snippet
             if let Some(cap) = ctx.config.snippet_cap {
                 if let Some(trait_) = impl_.trait_() {
-                    edit.add_placeholder_snippet(cap, trait_);
+                    let placeholder = edit.make_placeholder_snippet(cap);
+                    editor.add_annotation(trait_.syntax(), placeholder);
                 }
 
                 if let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) {
-                    edit.add_tabstop_after_token(cap, l_curly);
+                    let tabstop = edit.make_tabstop_after(cap);
+                    editor.add_annotation(l_curly, tabstop);
                 }
             }
 
-            insert_impl(impl_, &edit.make_mut(nominal));
+            insert_impl(&mut editor, &impl_, &nominal);
+            edit.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index bab2ccf3f33..4ddab2cfad0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -1,6 +1,6 @@
-use ide_db::famous_defs::FamousDefs;
+use ide_db::{famous_defs::FamousDefs, traits::resolve_target_trait};
 use syntax::{
-    AstNode,
+    AstNode, T,
     ast::{self, edit_in_place::Indent, make},
     ted,
 };
@@ -32,7 +32,7 @@ use crate::{AssistContext, AssistId, Assists};
 //
 // $0impl<T> core::ops::IndexMut<Axis> for [T; 3] {
 //     fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
-//         &self[index as usize]
+//         &mut self[index as usize]
 //     }
 // }
 //
@@ -48,36 +48,34 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
     let impl_def = ctx.find_node_at_offset::<ast::Impl>()?.clone_for_update();
     let indent = impl_def.indent_level();
 
-    let trait_ = impl_def.trait_()?;
-    if let ast::Type::PathType(trait_path) = trait_ {
-        let trait_type = ctx.sema.resolve_trait(&trait_path.path()?)?;
-        let scope = ctx.sema.scope(trait_path.syntax())?;
-        if trait_type != FamousDefs(&ctx.sema, scope.krate()).core_convert_Index()? {
-            return None;
-        }
-    }
+    let ast::Type::PathType(path) = impl_def.trait_()? else {
+        return None;
+    };
+    let trait_name = path.path()?.segment()?.name_ref()?;
+
+    let scope = ctx.sema.scope(impl_def.trait_()?.syntax())?;
+    let famous = FamousDefs(&ctx.sema, scope.krate());
+
+    let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
+    let trait_new = get_trait_mut(&trait_, famous)?;
 
     // Index -> IndexMut
-    let index_trait = impl_def
-        .syntax()
-        .descendants()
-        .filter_map(ast::NameRef::cast)
-        .find(|it| it.text() == "Index")?;
-    ted::replace(
-        index_trait.syntax(),
-        make::path_segment(make::name_ref("IndexMut")).clone_for_update().syntax(),
-    );
+    ted::replace(trait_name.syntax(), make::name_ref(trait_new).clone_for_update().syntax());
 
     // index -> index_mut
-    let trait_method_name = impl_def
+    let (trait_method_name, new_trait_method_name) = impl_def
         .syntax()
         .descendants()
         .filter_map(ast::Name::cast)
-        .find(|it| it.text() == "index")?;
-    ted::replace(trait_method_name.syntax(), make::name("index_mut").clone_for_update().syntax());
+        .find_map(process_method_name)?;
+    ted::replace(
+        trait_method_name.syntax(),
+        make::name(new_trait_method_name).clone_for_update().syntax(),
+    );
 
-    let type_alias = impl_def.syntax().descendants().find_map(ast::TypeAlias::cast)?;
-    ted::remove(type_alias.syntax());
+    if let Some(type_alias) = impl_def.syntax().descendants().find_map(ast::TypeAlias::cast) {
+        ted::remove(type_alias.syntax());
+    }
 
     // &self -> &mut self
     let mut_self_param = make::mut_self_param();
@@ -87,15 +85,14 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
 
     // &Self::Output -> &mut Self::Output
     let ret_type = impl_def.syntax().descendants().find_map(ast::RetType::cast)?;
-    ted::replace(
-        ret_type.syntax(),
-        make::ret_type(make::ty("&mut Self::Output")).clone_for_update().syntax(),
-    );
+    let new_ret_type = process_ret_type(&ret_type)?;
+    ted::replace(ret_type.syntax(), make::ret_type(new_ret_type).clone_for_update().syntax());
 
     let fn_ = impl_def.assoc_item_list()?.assoc_items().find_map(|it| match it {
         ast::AssocItem::Fn(f) => Some(f),
         _ => None,
     })?;
+    let _ = process_ref_mut(&fn_);
 
     let assoc_list = make::assoc_item_list().clone_for_update();
     ted::replace(impl_def.assoc_item_list()?.syntax(), assoc_list.syntax());
@@ -104,7 +101,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
     let target = impl_def.syntax().text_range();
     acc.add(
         AssistId::generate("generate_mut_trait_impl"),
-        "Generate `IndexMut` impl from this `Index` trait",
+        format!("Generate `{trait_new}` impl from this `{trait_name}` trait"),
         target,
         |edit| {
             edit.insert(target.start(), format!("$0{impl_def}\n\n{indent}"));
@@ -112,6 +109,52 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
     )
 }
 
+fn process_ref_mut(fn_: &ast::Fn) -> Option<()> {
+    let expr = fn_.body()?.tail_expr()?;
+    match &expr {
+        ast::Expr::RefExpr(ref_expr) if ref_expr.mut_token().is_none() => {
+            ted::insert_all_raw(
+                ted::Position::after(ref_expr.amp_token()?),
+                vec![make::token(T![mut]).into(), make::tokens::whitespace(" ").into()],
+            );
+        }
+        _ => {}
+    }
+    None
+}
+
+fn get_trait_mut(apply_trait: &hir::Trait, famous: FamousDefs<'_, '_>) -> Option<&'static str> {
+    let trait_ = Some(apply_trait);
+    if trait_ == famous.core_convert_Index().as_ref() {
+        return Some("IndexMut");
+    }
+    if trait_ == famous.core_convert_AsRef().as_ref() {
+        return Some("AsMut");
+    }
+    if trait_ == famous.core_borrow_Borrow().as_ref() {
+        return Some("BorrowMut");
+    }
+    None
+}
+
+fn process_method_name(name: ast::Name) -> Option<(ast::Name, &'static str)> {
+    let new_name = match &*name.text() {
+        "index" => "index_mut",
+        "as_ref" => "as_mut",
+        "borrow" => "borrow_mut",
+        _ => return None,
+    };
+    Some((name, new_name))
+}
+
+fn process_ret_type(ref_ty: &ast::RetType) -> Option<ast::Type> {
+    let ty = ref_ty.ty()?;
+    let ast::Type::RefType(ref_type) = ty else {
+        return None;
+    };
+    Some(make::ty_ref(ref_type.ty()?, true))
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -139,7 +182,7 @@ pub enum Axis { X = 0, Y = 1, Z = 2 }
 
 $0impl<T> core::ops::IndexMut<Axis> for [T; 3] {
     fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
-        &self[index as usize]
+        &mut self[index as usize]
     }
 }
 
@@ -188,6 +231,35 @@ impl<T> core::ops::Index<Axis> for [T; 3] where T: Copy {
 }
 "#,
         );
+
+        check_assist(
+            generate_mut_trait_impl,
+            r#"
+//- minicore: as_ref
+struct Foo(i32);
+
+impl core::convert::AsRef$0<i32> for Foo {
+    fn as_ref(&self) -> &i32 {
+        &self.0
+    }
+}
+"#,
+            r#"
+struct Foo(i32);
+
+$0impl core::convert::AsMut<i32> for Foo {
+    fn as_mut(&mut self) -> &mut i32 {
+        &mut self.0
+    }
+}
+
+impl core::convert::AsRef<i32> for Foo {
+    fn as_ref(&self) -> &i32 {
+        &self.0
+    }
+}
+"#,
+        );
     }
 
     #[test]
@@ -287,5 +359,13 @@ pub trait Index<Idx: ?Sized> {}
 impl<T> Index$0<i32> for [T; 3] {}
 "#,
         );
+        check_assist_not_applicable(
+            generate_mut_trait_impl,
+            r#"
+pub trait AsRef<T: ?Sized> {}
+
+impl AsRef$0<i32> for [T; 3] {}
+"#,
+        );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index 4837f92f934..51c2f65e025 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -1,5 +1,6 @@
 use ide_db::{
-    imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
+    imports::import_assets::item_for_path_search, syntax_helpers::suggest_name::NameGenerator,
+    use_trivial_constructor::use_trivial_constructor,
 };
 use syntax::{
     ast::{self, AstNode, HasName, HasVisibility, StructKind, edit_in_place::Indent, make},
@@ -35,10 +36,30 @@ use crate::{
 pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 
-    // We want to only apply this to non-union structs with named fields
     let field_list = match strukt.kind() {
-        StructKind::Record(named) => named,
-        _ => return None,
+        StructKind::Record(named) => {
+            named.fields().filter_map(|f| Some((f.name()?, f.ty()?))).collect::<Vec<_>>()
+        }
+        StructKind::Tuple(tuple) => {
+            let mut name_generator = NameGenerator::default();
+            tuple
+                .fields()
+                .enumerate()
+                .filter_map(|(i, f)| {
+                    let ty = f.ty()?;
+                    let name = match name_generator.for_type(
+                        &ctx.sema.resolve_type(&ty)?,
+                        ctx.db(),
+                        ctx.edition(),
+                    ) {
+                        Some(name) => name,
+                        None => name_generator.suggest_name(&format!("_{i}")),
+                    };
+                    Some((make::name(name.as_str()), f.ty()?))
+                })
+                .collect::<Vec<_>>()
+        }
+        StructKind::Unit => return None,
     };
 
     // Return early if we've found an existing new fn
@@ -50,11 +71,9 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     let target = strukt.syntax().text_range();
     acc.add(AssistId::generate("generate_new"), "Generate `new`", target, |builder| {
         let trivial_constructors = field_list
-            .fields()
-            .map(|f| {
-                let name = f.name()?;
-
-                let ty = ctx.sema.resolve_type(&f.ty()?)?;
+            .iter()
+            .map(|(name, ty)| {
+                let ty = ctx.sema.resolve_type(ty)?;
 
                 let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
 
@@ -73,34 +92,44 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                     edition,
                 )?;
 
-                Some(make::record_expr_field(make::name_ref(&name.text()), Some(expr)))
+                Some((make::name_ref(&name.text()), Some(expr)))
             })
             .collect::<Vec<_>>();
 
-        let params = field_list.fields().enumerate().filter_map(|(i, f)| {
+        let params = field_list.iter().enumerate().filter_map(|(i, (name, ty))| {
             if trivial_constructors[i].is_none() {
-                let name = f.name()?;
-                let ty = f.ty()?;
-
-                Some(make::param(make::ident_pat(false, false, name).into(), ty))
+                Some(make::param(make::ident_pat(false, false, name.clone()).into(), ty.clone()))
             } else {
                 None
             }
         });
         let params = make::param_list(None, params);
 
-        let fields = field_list.fields().enumerate().filter_map(|(i, f)| {
-            let constructor = trivial_constructors[i].clone();
-            if constructor.is_some() {
+        let fields = field_list.iter().enumerate().map(|(i, (name, _))| {
+            if let Some(constructor) = trivial_constructors[i].clone() {
                 constructor
             } else {
-                Some(make::record_expr_field(make::name_ref(&f.name()?.text()), None))
+                (make::name_ref(&name.text()), None)
             }
         });
-        let fields = make::record_expr_field_list(fields);
 
-        let record_expr = make::record_expr(make::ext::ident_path("Self"), fields);
-        let body = make::block_expr(None, Some(record_expr.into()));
+        let tail_expr: ast::Expr = match strukt.kind() {
+            StructKind::Record(_) => {
+                let fields = fields.map(|(name, expr)| make::record_expr_field(name, expr));
+                let fields = make::record_expr_field_list(fields);
+                make::record_expr(make::ext::ident_path("Self"), fields).into()
+            }
+            StructKind::Tuple(_) => {
+                let args = fields.map(|(arg, expr)| {
+                    let arg = || make::expr_path(make::path_unqualified(make::path_segment(arg)));
+                    expr.unwrap_or_else(arg)
+                });
+                let arg_list = make::arg_list(args);
+                make::expr_call(make::expr_path(make::ext::ident_path("Self")), arg_list).into()
+            }
+            StructKind::Unit => unreachable!(),
+        };
+        let body = make::block_expr(None, tail_expr.into());
 
         let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self")));
 
@@ -120,8 +149,35 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
         .clone_for_update();
         fn_.indent(1.into());
 
-        // Add a tabstop before the name
         if let Some(cap) = ctx.config.snippet_cap {
+            match strukt.kind() {
+                StructKind::Tuple(_) => {
+                    let struct_args = fn_
+                        .body()
+                        .unwrap()
+                        .syntax()
+                        .descendants()
+                        .filter(|it| syntax::ast::ArgList::can_cast(it.kind()))
+                        .flat_map(|args| args.children())
+                        .filter(|it| syntax::ast::PathExpr::can_cast(it.kind()))
+                        .enumerate()
+                        .filter_map(|(i, node)| {
+                            if trivial_constructors[i].is_none() { Some(node) } else { None }
+                        });
+                    if let Some(fn_params) = fn_.param_list() {
+                        for (struct_arg, fn_param) in struct_args.zip(fn_params.params()) {
+                            if let Some(fn_pat) = fn_param.pat() {
+                                let fn_pat = fn_pat.syntax().clone();
+                                builder
+                                    .add_placeholder_snippet_group(cap, vec![struct_arg, fn_pat]);
+                            }
+                        }
+                    }
+                }
+                _ => {}
+            }
+
+            // Add a tabstop before the name
             if let Some(name) = fn_.name() {
                 builder.add_tabstop_before(cap, name);
             }
@@ -157,7 +213,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
 }
 
 #[cfg(test)]
-mod tests {
+mod record_tests {
     use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 
     use super::*;
@@ -695,3 +751,308 @@ impl<T> Source<T> {
         );
     }
 }
+
+#[cfg(test)]
+mod tuple_tests {
+    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
+
+    use super::*;
+
+    #[test]
+    fn test_generate_new_with_zst_fields() {
+        check_assist(
+            generate_new,
+            r#"
+struct Empty;
+
+struct Foo(Empty$0);
+"#,
+            r#"
+struct Empty;
+
+struct Foo(Empty);
+
+impl Foo {
+    fn $0new() -> Self {
+        Self(Empty)
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+struct Empty;
+
+struct Foo(String, Empty$0);
+"#,
+            r#"
+struct Empty;
+
+struct Foo(String, Empty);
+
+impl Foo {
+    fn $0new(${1:_0}: String) -> Self {
+        Self(${1:_0}, Empty)
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+enum Empty { Bar }
+
+struct Foo(Empty$0);
+"#,
+            r#"
+enum Empty { Bar }
+
+struct Foo(Empty);
+
+impl Foo {
+    fn $0new() -> Self {
+        Self(Empty::Bar)
+    }
+}
+"#,
+        );
+
+        // make sure the assist only works on unit variants
+        check_assist(
+            generate_new,
+            r#"
+struct Empty {}
+
+struct Foo(Empty$0);
+"#,
+            r#"
+struct Empty {}
+
+struct Foo(Empty);
+
+impl Foo {
+    fn $0new(${1:empty}: Empty) -> Self {
+        Self(${1:empty})
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+enum Empty { Bar {} }
+
+struct Foo(Empty$0);
+"#,
+            r#"
+enum Empty { Bar {} }
+
+struct Foo(Empty);
+
+impl Foo {
+    fn $0new(${1:empty}: Empty) -> Self {
+        Self(${1:empty})
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_generate_new() {
+        check_assist(
+            generate_new,
+            r#"
+struct Foo($0);
+"#,
+            r#"
+struct Foo();
+
+impl Foo {
+    fn $0new() -> Self {
+        Self()
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+struct Foo<T: Clone>($0);
+"#,
+            r#"
+struct Foo<T: Clone>();
+
+impl<T: Clone> Foo<T> {
+    fn $0new() -> Self {
+        Self()
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+struct Foo<'a, T: Foo<'a>>($0);
+"#,
+            r#"
+struct Foo<'a, T: Foo<'a>>();
+
+impl<'a, T: Foo<'a>> Foo<'a, T> {
+    fn $0new() -> Self {
+        Self()
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+struct Foo(String$0);
+"#,
+            r#"
+struct Foo(String);
+
+impl Foo {
+    fn $0new(${1:_0}: String) -> Self {
+        Self(${1:_0})
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+struct Vec<T> { };
+struct Foo(String, Vec<i32>$0);
+"#,
+            r#"
+struct Vec<T> { };
+struct Foo(String, Vec<i32>);
+
+impl Foo {
+    fn $0new(${1:_0}: String, ${2:items}: Vec<i32>) -> Self {
+        Self(${1:_0}, ${2:items})
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn check_that_visibility_modifiers_dont_get_brought_in() {
+        check_assist(
+            generate_new,
+            r#"
+struct Vec<T> { };
+struct Foo(pub String, pub Vec<i32>$0);
+"#,
+            r#"
+struct Vec<T> { };
+struct Foo(pub String, pub Vec<i32>);
+
+impl Foo {
+    fn $0new(${1:_0}: String, ${2:items}: Vec<i32>) -> Self {
+        Self(${1:_0}, ${2:items})
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn generate_new_not_applicable_if_fn_exists() {
+        check_assist_not_applicable(
+            generate_new,
+            r#"
+struct Foo($0);
+
+impl Foo {
+    fn new() -> Self {
+        Self
+    }
+}
+"#,
+        );
+
+        check_assist_not_applicable(
+            generate_new,
+            r#"
+struct Foo($0);
+
+impl Foo {
+    fn New() -> Self {
+        Self
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn generate_new_target() {
+        check_assist_target(
+            generate_new,
+            r#"
+struct SomeThingIrrelevant;
+/// Has a lifetime parameter
+struct Foo<'a, T: Foo<'a>>($0);
+struct EvenMoreIrrelevant;
+"#,
+            "/// Has a lifetime parameter
+struct Foo<'a, T: Foo<'a>>();",
+        );
+    }
+
+    #[test]
+    fn test_unrelated_new() {
+        check_assist(
+            generate_new,
+            r#"
+pub struct AstId<N: AstNode> {
+    file_id: HirFileId,
+    file_ast_id: FileAstId<N>,
+}
+
+impl<N: AstNode> AstId<N> {
+    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
+        AstId { file_id, file_ast_id }
+    }
+}
+
+pub struct Source<T>(pub HirFileId,$0 pub T);
+
+impl<T> Source<T> {
+    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
+        Source(self.file_id, f(self.ast))
+    }
+}
+"#,
+            r#"
+pub struct AstId<N: AstNode> {
+    file_id: HirFileId,
+    file_ast_id: FileAstId<N>,
+}
+
+impl<N: AstNode> AstId<N> {
+    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
+        AstId { file_id, file_ast_id }
+    }
+}
+
+pub struct Source<T>(pub HirFileId, pub T);
+
+impl<T> Source<T> {
+    pub fn $0new(${1:_0}: HirFileId, ${2:_1}: T) -> Self {
+        Self(${1:_0}, ${2:_1})
+    }
+
+    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
+        Source(self.file_id, f(self.ast))
+    }
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
new file mode 100644
index 00000000000..4e95ceb2e85
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs
@@ -0,0 +1,1000 @@
+use ast::make;
+use hir::{HasCrate, ModuleDef, Semantics};
+use ide_db::{
+    RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast,
+    imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
+};
+use syntax::{
+    TokenText,
+    ast::{self, AstNode, HasGenericParams, HasName, edit, edit_in_place::Indent},
+};
+
+use crate::{
+    AssistId,
+    assist_context::{AssistContext, Assists},
+    utils::add_cfg_attrs_to,
+};
+
+// Assist: generate_single_field_struct_from
+//
+// Implement From for a single field structure, ignore trivial types.
+//
+// ```
+// # //- minicore: from, phantom_data
+// use core::marker::PhantomData;
+// struct $0Foo<T> {
+//     id: i32,
+//     _phantom_data: PhantomData<T>,
+// }
+// ```
+// ->
+// ```
+// use core::marker::PhantomData;
+// struct Foo<T> {
+//     id: i32,
+//     _phantom_data: PhantomData<T>,
+// }
+//
+// impl<T> From<i32> for Foo<T> {
+//     fn from(id: i32) -> Self {
+//         Self { id, _phantom_data: PhantomData }
+//     }
+// }
+// ```
+pub(crate) fn generate_single_field_struct_from(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
+    let strukt_name = ctx.find_node_at_offset::<ast::Name>()?;
+    let adt = ast::Adt::cast(strukt_name.syntax().parent()?)?;
+    let ast::Adt::Struct(strukt) = adt else {
+        return None;
+    };
+
+    let sema = &ctx.sema;
+    let (names, types) = get_fields(&strukt)?;
+
+    let module = sema.scope(strukt.syntax())?.module();
+    let constructors = make_constructors(ctx, module, &types);
+
+    if constructors.iter().filter(|expr| expr.is_none()).count() != 1 {
+        return None;
+    }
+    let main_field_i = constructors.iter().position(Option::is_none)?;
+    if from_impl_exists(&strukt, main_field_i, &ctx.sema).is_some() {
+        return None;
+    }
+
+    let main_field_name =
+        names.as_ref().map_or(TokenText::borrowed("value"), |names| names[main_field_i].text());
+    let main_field_ty = types[main_field_i].clone();
+
+    acc.add(
+        AssistId::generate("generate_single_field_struct_from"),
+        "Generate single field `From`",
+        strukt.syntax().text_range(),
+        |builder| {
+            let indent = strukt.indent_level();
+            let ty_where_clause = strukt.where_clause();
+            let type_gen_params = strukt.generic_param_list();
+            let type_gen_args = type_gen_params.as_ref().map(|params| params.to_generic_args());
+            let trait_gen_args = Some(make::generic_arg_list([ast::GenericArg::TypeArg(
+                make::type_arg(main_field_ty.clone()),
+            )]));
+
+            let ty = make::ty(&strukt_name.text());
+
+            let constructor =
+                make_adt_constructor(names.as_deref(), constructors, &main_field_name);
+            let body = make::block_expr([], Some(constructor));
+
+            let fn_ = make::fn_(
+                None,
+                make::name("from"),
+                None,
+                None,
+                make::param_list(
+                    None,
+                    [make::param(
+                        make::path_pat(make::path_from_text(&main_field_name)),
+                        main_field_ty,
+                    )],
+                ),
+                body,
+                Some(make::ret_type(make::ty("Self"))),
+                false,
+                false,
+                false,
+                false,
+            )
+            .clone_for_update();
+
+            fn_.indent(1.into());
+
+            let impl_ = make::impl_trait(
+                false,
+                None,
+                trait_gen_args,
+                type_gen_params,
+                type_gen_args,
+                false,
+                make::ty("From"),
+                ty.clone(),
+                None,
+                ty_where_clause.map(|wc| edit::AstNodeEdit::reset_indent(&wc)),
+                None,
+            )
+            .clone_for_update();
+
+            impl_.get_or_create_assoc_item_list().add_item(fn_.into());
+
+            add_cfg_attrs_to(&strukt, &impl_);
+
+            impl_.reindent_to(indent);
+
+            builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}"));
+        },
+    )
+}
+
+fn make_adt_constructor(
+    names: Option<&[ast::Name]>,
+    constructors: Vec<Option<ast::Expr>>,
+    main_field_name: &TokenText<'_>,
+) -> ast::Expr {
+    if let Some(names) = names {
+        let fields = make::record_expr_field_list(names.iter().zip(constructors).map(
+            |(name, initializer)| {
+                make::record_expr_field(make::name_ref(&name.text()), initializer)
+            },
+        ));
+        make::record_expr(make::path_from_text("Self"), fields).into()
+    } else {
+        let arg_list = make::arg_list(constructors.into_iter().map(|expr| {
+            expr.unwrap_or_else(|| make::expr_path(make::path_from_text(main_field_name)))
+        }));
+        make::expr_call(make::expr_path(make::path_from_text("Self")), arg_list).into()
+    }
+}
+
+fn make_constructors(
+    ctx: &AssistContext<'_>,
+    module: hir::Module,
+    types: &[ast::Type],
+) -> Vec<Option<ast::Expr>> {
+    let (db, sema) = (ctx.db(), &ctx.sema);
+    types
+        .iter()
+        .map(|ty| {
+            let ty = sema.resolve_type(ty)?;
+            if ty.is_unit() {
+                return Some(make::expr_tuple([]).into());
+            }
+            let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into();
+            let edition = module.krate().edition(db);
+
+            let ty_path = module.find_path(
+                db,
+                item_for_path_search(db, item_in_ns)?,
+                ctx.config.import_path_config(),
+            )?;
+
+            use_trivial_constructor(db, mod_path_to_ast(&ty_path, edition), &ty, edition)
+        })
+        .collect()
+}
+
+fn get_fields(strukt: &ast::Struct) -> Option<(Option<Vec<ast::Name>>, Vec<ast::Type>)> {
+    Some(match strukt.kind() {
+        ast::StructKind::Unit => return None,
+        ast::StructKind::Record(fields) => {
+            let names = fields.fields().map(|field| field.name()).collect::<Option<_>>()?;
+            let types = fields.fields().map(|field| field.ty()).collect::<Option<_>>()?;
+            (Some(names), types)
+        }
+        ast::StructKind::Tuple(fields) => {
+            (None, fields.fields().map(|field| field.ty()).collect::<Option<_>>()?)
+        }
+    })
+}
+
+fn from_impl_exists(
+    strukt: &ast::Struct,
+    main_field_i: usize,
+    sema: &Semantics<'_, RootDatabase>,
+) -> Option<()> {
+    let db = sema.db;
+    let strukt = sema.to_def(strukt)?;
+    let krate = strukt.krate(db);
+    let from_trait = FamousDefs(sema, krate).core_convert_From()?;
+    let ty = strukt.fields(db).get(main_field_i)?.ty(db);
+
+    strukt.ty(db).impls_trait(db, from_trait, &[ty]).then_some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::generate_single_field_struct_from;
+
+    #[test]
+    fn works() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo {
+                foo: i32,
+            }
+            "#,
+            r#"
+            struct Foo {
+                foo: i32,
+            }
+
+            impl From<i32> for Foo {
+                fn from(foo: i32) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from, phantom_data
+            struct $0Foo {
+                b1: (),
+                b2: core::marker::PhantomData,
+                foo: i32,
+                a1: (),
+                a2: core::marker::PhantomData,
+            }
+            "#,
+            r#"
+            struct Foo {
+                b1: (),
+                b2: core::marker::PhantomData,
+                foo: i32,
+                a1: (),
+                a2: core::marker::PhantomData,
+            }
+
+            impl From<i32> for Foo {
+                fn from(foo: i32) -> Self {
+                    Self { b1: (), b2: core::marker::PhantomData, foo, a1: (), a2: core::marker::PhantomData }
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn cfgs() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            #[cfg(feature = "foo")]
+            #[cfg(test)]
+            struct $0Foo {
+                foo: i32,
+            }
+            "#,
+            r#"
+            #[cfg(feature = "foo")]
+            #[cfg(test)]
+            struct Foo {
+                foo: i32,
+            }
+
+            #[cfg(feature = "foo")]
+            #[cfg(test)]
+            impl From<i32> for Foo {
+                fn from(foo: i32) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn indent() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            mod foo {
+                struct $0Foo {
+                    foo: i32,
+                }
+            }
+            "#,
+            r#"
+            mod foo {
+                struct Foo {
+                    foo: i32,
+                }
+
+                impl From<i32> for Foo {
+                    fn from(foo: i32) -> Self {
+                        Self { foo }
+                    }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            mod foo {
+                mod bar {
+                    struct $0Foo {
+                        foo: i32,
+                    }
+                }
+            }
+            "#,
+            r#"
+            mod foo {
+                mod bar {
+                    struct Foo {
+                        foo: i32,
+                    }
+
+                    impl From<i32> for Foo {
+                        fn from(foo: i32) -> Self {
+                            Self { foo }
+                        }
+                    }
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn where_clause_indent() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            mod foo {
+                mod bar {
+                    trait Trait {}
+                    struct $0Foo<T>
+                    where
+                        T: Trait,
+                    {
+                        foo: T,
+                    }
+                }
+            }
+            "#,
+            r#"
+            mod foo {
+                mod bar {
+                    trait Trait {}
+                    struct Foo<T>
+                    where
+                        T: Trait,
+                    {
+                        foo: T,
+                    }
+
+                    impl<T> From<T> for Foo<T>
+                    where
+                        T: Trait,
+                    {
+                        fn from(foo: T) -> Self {
+                            Self { foo }
+                        }
+                    }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            mod foo {
+                mod bar {
+                    trait Trait<const B: bool> {}
+                    struct $0Foo<T>
+                    where
+                        T: Trait<{
+                            true
+                        }>
+                    {
+                        foo: T,
+                    }
+                }
+            }
+            "#,
+            r#"
+            mod foo {
+                mod bar {
+                    trait Trait<const B: bool> {}
+                    struct Foo<T>
+                    where
+                        T: Trait<{
+                            true
+                        }>
+                    {
+                        foo: T,
+                    }
+
+                    impl<T> From<T> for Foo<T>
+                    where
+                        T: Trait<{
+                            true
+                        }>
+                    {
+                        fn from(foo: T) -> Self {
+                            Self { foo }
+                        }
+                    }
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn generics() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T> {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T> {
+                foo: T,
+            }
+
+            impl<T> From<T> for Foo<T> {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send> {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send> {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T> {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send> where T: Sync,{
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send> where T: Sync,{
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where T: Sync,
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send> where T: Sync {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send> where T: Sync {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where T: Sync
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send> where T: Sync, Self: Send {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send> where T: Sync, Self: Send {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where T: Sync, Self: Send
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send>
+            where T: Sync, Self: Send
+            {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send>
+            where T: Sync, Self: Send
+            {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where T: Sync, Self: Send
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send>
+            where T: Sync, Self: Send,
+            {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send>
+            where T: Sync, Self: Send,
+            {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where T: Sync, Self: Send,
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send>
+            where T: Sync,
+                  Self: Send,
+            {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send>
+            where T: Sync,
+                  Self: Send,
+            {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where T: Sync,
+                  Self: Send,
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send>
+            where
+                T: Sync,
+                Self: Send,
+            {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send>
+            where
+                T: Sync,
+                Self: Send,
+            {
+                foo: T,
+            }
+
+            impl<T: Send> From<T> for Foo<T>
+            where
+                T: Sync,
+                Self: Send,
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T: Send + Sync>
+            where
+                T: Sync,
+                Self: Send,
+            {
+                foo: T,
+            }
+            "#,
+            r#"
+            struct Foo<T: Send + Sync>
+            where
+                T: Sync,
+                Self: Send,
+            {
+                foo: T,
+            }
+
+            impl<T: Send + Sync> From<T> for Foo<T>
+            where
+                T: Sync,
+                Self: Send,
+            {
+                fn from(foo: T) -> Self {
+                    Self { foo }
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn tuple() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32);
+            "#,
+            r#"
+            struct Foo(i32);
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(value)
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T>(T);
+            "#,
+            r#"
+            struct Foo<T>(T);
+
+            impl<T> From<T> for Foo<T> {
+                fn from(value: T) -> Self {
+                    Self(value)
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn trivial() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from, phantom_data
+            use core::marker::PhantomData;
+            struct $0Foo(i32, PhantomData<i32>);
+            "#,
+            r#"
+            use core::marker::PhantomData;
+            struct Foo(i32, PhantomData<i32>);
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(value, PhantomData)
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from, phantom_data
+            use core::marker::PhantomData;
+            struct $0Foo(i32, PhantomData<()>);
+            "#,
+            r#"
+            use core::marker::PhantomData;
+            struct Foo(i32, PhantomData<()>);
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(value, PhantomData)
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from, phantom_data
+            use core::marker::PhantomData;
+            struct $0Foo(PhantomData<()>, i32, PhantomData<()>);
+            "#,
+            r#"
+            use core::marker::PhantomData;
+            struct Foo(PhantomData<()>, i32, PhantomData<()>);
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(PhantomData, value, PhantomData)
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from, phantom_data
+            use core::marker::PhantomData;
+            struct $0Foo<T>(PhantomData<T>, i32, PhantomData<()>);
+            "#,
+            r#"
+            use core::marker::PhantomData;
+            struct Foo<T>(PhantomData<T>, i32, PhantomData<()>);
+
+            impl<T> From<i32> for Foo<T> {
+                fn from(value: i32) -> Self {
+                    Self(PhantomData, value, PhantomData)
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn unit() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32, ());
+            "#,
+            r#"
+            struct Foo(i32, ());
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(value, ())
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo((), i32, ());
+            "#,
+            r#"
+            struct Foo((), i32, ());
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self((), value, ())
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo((), (), i32, ());
+            "#,
+            r#"
+            struct Foo((), (), i32, ());
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self((), (), value, ())
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn invalid_multiple_main_field() {
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32, i32);
+            "#,
+        );
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T>(i32, T);
+            "#,
+        );
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T>(T, T);
+            "#,
+        );
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo<T> { foo: T, bar: i32 }
+            "#,
+        );
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo { foo: i32, bar: i64 }
+            "#,
+        );
+    }
+
+    #[test]
+    fn exists_other_from() {
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32);
+
+            impl From<&i32> for Foo {
+                fn from(value: &i32) -> Self {
+                    todo!()
+                }
+            }
+            "#,
+            r#"
+            struct Foo(i32);
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(value)
+                }
+            }
+
+            impl From<&i32> for Foo {
+                fn from(value: &i32) -> Self {
+                    todo!()
+                }
+            }
+            "#,
+        );
+        check_assist(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32);
+
+            type X = i32;
+
+            impl From<&X> for Foo {
+                fn from(value: &X) -> Self {
+                    todo!()
+                }
+            }
+            "#,
+            r#"
+            struct Foo(i32);
+
+            impl From<i32> for Foo {
+                fn from(value: i32) -> Self {
+                    Self(value)
+                }
+            }
+
+            type X = i32;
+
+            impl From<&X> for Foo {
+                fn from(value: &X) -> Self {
+                    todo!()
+                }
+            }
+            "#,
+        );
+    }
+
+    #[test]
+    fn exists_from() {
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32);
+
+            impl From<i32> for Foo {
+                fn from(_: i32) -> Self {
+                    todo!()
+                }
+            }
+            "#,
+        );
+        check_assist_not_applicable(
+            generate_single_field_struct_from,
+            r#"
+            //- minicore: from
+            struct $0Foo(i32);
+
+            type X = i32;
+
+            impl From<X> for Foo {
+                fn from(_: X) -> Self {
+                    todo!()
+                }
+            }
+            "#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
index 5f626d29571..1b0c3139353 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -1,7 +1,8 @@
 use syntax::{
     AstNode,
-    ast::{self, make},
-    ted,
+    algo::find_node_at_range,
+    ast::{self, syntax_factory::SyntaxFactory},
+    syntax_editor::SyntaxEditor,
 };
 
 use crate::{
@@ -66,33 +67,51 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             return None;
         }
     }
-
+    let target = tgt.syntax().text_range();
+
+    let edit_tgt = tgt.syntax().clone_subtree();
+    let assignments: Vec<_> = collector
+        .assignments
+        .into_iter()
+        .filter_map(|(stmt, rhs)| {
+            Some((
+                find_node_at_range::<ast::BinExpr>(
+                    &edit_tgt,
+                    stmt.syntax().text_range() - target.start(),
+                )?,
+                find_node_at_range::<ast::Expr>(
+                    &edit_tgt,
+                    rhs.syntax().text_range() - target.start(),
+                )?,
+            ))
+        })
+        .collect();
+
+    let mut editor = SyntaxEditor::new(edit_tgt);
+    for (stmt, rhs) in assignments {
+        let mut stmt = stmt.syntax().clone();
+        if let Some(parent) = stmt.parent() {
+            if ast::ExprStmt::cast(parent.clone()).is_some() {
+                stmt = parent.clone();
+            }
+        }
+        editor.replace(stmt, rhs.syntax());
+    }
+    let new_tgt_root = editor.finish().new_root().clone();
+    let new_tgt = ast::Expr::cast(new_tgt_root)?;
     acc.add(
         AssistId::refactor_extract("pull_assignment_up"),
         "Pull assignment up",
-        tgt.syntax().text_range(),
+        target,
         move |edit| {
-            let assignments: Vec<_> = collector
-                .assignments
-                .into_iter()
-                .map(|(stmt, rhs)| (edit.make_mut(stmt), rhs.clone_for_update()))
-                .collect();
-
-            let tgt = edit.make_mut(tgt);
-
-            for (stmt, rhs) in assignments {
-                let mut stmt = stmt.syntax().clone();
-                if let Some(parent) = stmt.parent() {
-                    if ast::ExprStmt::cast(parent.clone()).is_some() {
-                        stmt = parent.clone();
-                    }
-                }
-                ted::replace(stmt, rhs.syntax());
-            }
-            let assign_expr = make::expr_assignment(collector.common_lhs, tgt.clone());
-            let assign_stmt = make::expr_stmt(assign_expr);
-
-            ted::replace(tgt.syntax(), assign_stmt.syntax().clone_for_update());
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = edit.make_editor(tgt.syntax());
+            let assign_expr = make.expr_assignment(collector.common_lhs, new_tgt.clone());
+            let assign_stmt = make.expr_stmt(assign_expr.into());
+
+            editor.replace(tgt.syntax(), assign_stmt.syntax());
+            editor.add_mappings(make.finish_with_mappings());
+            edit.add_file_edits(ctx.vfs_file_id(), editor);
         },
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 52ace03f3cf..9356d02706c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -1,8 +1,9 @@
 use itertools::Itertools;
 use syntax::{
-    Edition, NodeOrToken, SyntaxElement, T, TextRange, TextSize,
-    ast::{self, AstNode, AstToken, make},
-    match_ast, ted,
+    Edition, NodeOrToken, SyntaxNode, SyntaxToken, T,
+    ast::{self, AstNode, make},
+    match_ast,
+    syntax_editor::{Position, SyntaxEditor},
 };
 
 use crate::{AssistContext, AssistId, Assists};
@@ -40,21 +41,23 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
 
     let replacements =
         macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
-
-    acc.add(
-        AssistId::quick_fix("remove_dbg"),
-        "Remove dbg!()",
-        replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?,
-        |builder| {
-            for (range, expr) in replacements {
-                if let Some(expr) = expr {
-                    builder.replace(range, expr.to_string());
-                } else {
-                    builder.delete(range);
-                }
+    let target = replacements
+        .iter()
+        .flat_map(|(node_or_token, _)| node_or_token.iter())
+        .map(|t| t.text_range())
+        .reduce(|acc, range| acc.cover(range))?;
+    acc.add(AssistId::quick_fix("remove_dbg"), "Remove dbg!()", target, |builder| {
+        let mut editor = builder.make_editor(ctx.source_file().syntax());
+        for (range, expr) in replacements {
+            if let Some(expr) = expr {
+                editor.insert(Position::before(range[0].clone()), expr.syntax().clone_for_update());
+            }
+            for node_or_token in range {
+                editor.delete(node_or_token);
             }
-        },
-    )
+        }
+        builder.add_file_edits(ctx.vfs_file_id(), editor);
+    })
 }
 
 /// Returns `None` when either
@@ -63,7 +66,9 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
 /// - (`macro_expr` has no parent - is that possible?)
 ///
 /// Returns `Some(_, None)` when the macro call should just be removed.
-fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Option<ast::Expr>)> {
+fn compute_dbg_replacement(
+    macro_expr: ast::MacroExpr,
+) -> Option<(Vec<NodeOrToken<SyntaxNode, SyntaxToken>>, Option<ast::Expr>)> {
     let macro_call = macro_expr.macro_call()?;
     let tt = macro_call.token_tree()?;
     let r_delim = NodeOrToken::Token(tt.right_delimiter_token()?);
@@ -88,22 +93,22 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
             match_ast! {
                 match parent {
                     ast::StmtList(_) => {
-                        let range = macro_expr.syntax().text_range();
-                        let range = match whitespace_start(macro_expr.syntax().prev_sibling_or_token()) {
-                            Some(start) => range.cover_offset(start),
-                            None => range,
-                        };
-                        (range, None)
+                        let mut replace = vec![macro_expr.syntax().clone().into()];
+                        if let Some(prev_sibling) = macro_expr.syntax().prev_sibling_or_token()
+                            && prev_sibling.kind() == syntax::SyntaxKind::WHITESPACE {
+                                replace.push(prev_sibling);
+                        }
+                        (replace, None)
                     },
                     ast::ExprStmt(it) => {
-                        let range = it.syntax().text_range();
-                        let range = match whitespace_start(it.syntax().prev_sibling_or_token()) {
-                            Some(start) => range.cover_offset(start),
-                            None => range,
-                        };
-                        (range, None)
+                        let mut replace = vec![it.syntax().clone().into()];
+                        if let Some(prev_sibling) = it.syntax().prev_sibling_or_token()
+                            && prev_sibling.kind() == syntax::SyntaxKind::WHITESPACE {
+                                replace.push(prev_sibling);
+                        }
+                        (replace, None)
                     },
-                    _ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())),
+                    _ => (vec![macro_call.syntax().clone().into()], Some(make::ext::expr_unit())),
                 }
             }
         }
@@ -147,13 +152,13 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
             };
             let expr = replace_nested_dbgs(expr.clone());
             let expr = if wrap { make::expr_paren(expr).into() } else { expr.clone_subtree() };
-            (macro_call.syntax().text_range(), Some(expr))
+            (vec![macro_call.syntax().clone().into()], Some(expr))
         }
         // dbg!(expr0, expr1, ...)
         exprs => {
             let exprs = exprs.iter().cloned().map(replace_nested_dbgs);
             let expr = make::expr_tuple(exprs);
-            (macro_call.syntax().text_range(), Some(expr.into()))
+            (vec![macro_call.syntax().clone().into()], Some(expr.into()))
         }
     })
 }
@@ -178,8 +183,8 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
         return replaced;
     }
 
-    let expanded = expanded.clone_for_update();
-
+    let expanded = expanded.clone_subtree();
+    let mut editor = SyntaxEditor::new(expanded.syntax().clone());
     // We need to collect to avoid mutation during traversal.
     let macro_exprs: Vec<_> =
         expanded.syntax().descendants().filter_map(ast::MacroExpr::cast).collect();
@@ -191,17 +196,13 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
         };
 
         if let Some(expr) = expr_opt {
-            ted::replace(mac.syntax(), expr.syntax().clone_for_update());
+            editor.replace(mac.syntax(), expr.syntax().clone_for_update());
         } else {
-            ted::remove(mac.syntax());
+            editor.delete(mac.syntax());
         }
     }
-
-    expanded
-}
-
-fn whitespace_start(it: Option<SyntaxElement>) -> Option<TextSize> {
-    Some(it?.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
+    let expanded_syntax = editor.finish().new_root().clone();
+    ast::Expr::cast(expanded_syntax).unwrap()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index 62914ee7f38..5ef8ba46b9e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -64,13 +64,12 @@ pub(crate) fn replace_is_method_with_if_let_method(
                     let pat = make.tuple_struct_pat(make.ident_path(text), [var_pat.into()]);
                     let let_expr = make.expr_let(pat.into(), receiver);
 
-                    if let Some(cap) = ctx.config.snippet_cap {
-                        if let Some(ast::Pat::TupleStructPat(pat)) = let_expr.pat() {
-                            if let Some(first_var) = pat.fields().next() {
-                                let placeholder = edit.make_placeholder_snippet(cap);
-                                editor.add_annotation(first_var.syntax(), placeholder);
-                            }
-                        }
+                    if let Some(cap) = ctx.config.snippet_cap
+                        && let Some(ast::Pat::TupleStructPat(pat)) = let_expr.pat()
+                        && let Some(first_var) = pat.fields().next()
+                    {
+                        let placeholder = edit.make_placeholder_snippet(cap);
+                        editor.add_annotation(first_var.syntax(), placeholder);
                     }
 
                     editor.replace(call_expr.syntax(), let_expr.syntax());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index c2604432032..cde0d875e0d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -172,6 +172,7 @@ mod handlers {
     mod generate_is_empty_from_len;
     mod generate_mut_trait_impl;
     mod generate_new;
+    mod generate_single_field_struct_from;
     mod generate_trait_from_impl;
     mod inline_call;
     mod inline_const_as_literal;
@@ -305,6 +306,7 @@ mod handlers {
             generate_mut_trait_impl::generate_mut_trait_impl,
             generate_new::generate_new,
             generate_trait_from_impl::generate_trait_from_impl,
+            generate_single_field_struct_from::generate_single_field_struct_from,
             inline_call::inline_call,
             inline_call::inline_into_callers,
             inline_const_as_literal::inline_const_as_literal,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 72f7195cbd7..fc1c6928ff3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1933,7 +1933,7 @@ pub enum Axis { X = 0, Y = 1, Z = 2 }
 
 $0impl<T> core::ops::IndexMut<Axis> for [T; 3] {
     fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
-        &self[index as usize]
+        &mut self[index as usize]
     }
 }
 
@@ -1995,6 +1995,34 @@ impl Person {
 }
 
 #[test]
+fn doctest_generate_single_field_struct_from() {
+    check_doc_test(
+        "generate_single_field_struct_from",
+        r#####"
+//- minicore: from, phantom_data
+use core::marker::PhantomData;
+struct $0Foo<T> {
+    id: i32,
+    _phantom_data: PhantomData<T>,
+}
+"#####,
+        r#####"
+use core::marker::PhantomData;
+struct Foo<T> {
+    id: i32,
+    _phantom_data: PhantomData<T>,
+}
+
+impl<T> From<i32> for Foo<T> {
+    fn from(id: i32) -> Self {
+        Self { id, _phantom_data: PhantomData }
+    }
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_generate_trait_from_impl() {
     check_doc_test(
         "generate_trait_from_impl",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 87a4c2ef758..2c8cb6e4d91 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -594,12 +594,10 @@ fn generate_impl_text_inner(
     let generic_params = adt.generic_param_list().map(|generic_params| {
         let lifetime_params =
             generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
-        let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
-            match param {
+        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
+            let param = match param {
                 ast::TypeOrConstParam::Type(param) => {
-                    let param = param.clone_for_update();
                     // remove defaults since they can't be specified in impls
-                    param.remove_default();
                     let mut bounds =
                         param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
                     if let Some(trait_) = trait_text {
@@ -610,17 +608,16 @@ fn generate_impl_text_inner(
                         }
                     };
                     // `{ty_param}: {bounds}`
-                    let param =
-                        make::type_param(param.name().unwrap(), make::type_bound_list(bounds));
+                    let param = make::type_param(param.name()?, make::type_bound_list(bounds));
                     ast::GenericParam::TypeParam(param)
                 }
                 ast::TypeOrConstParam::Const(param) => {
-                    let param = param.clone_for_update();
                     // remove defaults since they can't be specified in impls
-                    param.remove_default();
+                    let param = make::const_param(param.name()?, param.ty()?);
                     ast::GenericParam::ConstParam(param)
                 }
-            }
+            };
+            Some(param)
         });
 
         make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
@@ -695,12 +692,10 @@ fn generate_impl_inner(
     let generic_params = adt.generic_param_list().map(|generic_params| {
         let lifetime_params =
             generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
-        let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
-            match param {
+        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
+            let param = match param {
                 ast::TypeOrConstParam::Type(param) => {
-                    let param = param.clone_for_update();
                     // remove defaults since they can't be specified in impls
-                    param.remove_default();
                     let mut bounds =
                         param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
                     if let Some(trait_) = &trait_ {
@@ -711,17 +706,16 @@ fn generate_impl_inner(
                         }
                     };
                     // `{ty_param}: {bounds}`
-                    let param =
-                        make::type_param(param.name().unwrap(), make::type_bound_list(bounds));
+                    let param = make::type_param(param.name()?, make::type_bound_list(bounds));
                     ast::GenericParam::TypeParam(param)
                 }
                 ast::TypeOrConstParam::Const(param) => {
-                    let param = param.clone_for_update();
                     // remove defaults since they can't be specified in impls
-                    param.remove_default();
+                    let param = make::const_param(param.name()?, param.ty()?);
                     ast::GenericParam::ConstParam(param)
                 }
-            }
+            };
+            Some(param)
         });
 
         make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
@@ -749,16 +743,23 @@ fn generate_impl_inner(
     .clone_for_update();
 
     // Copy any cfg attrs from the original adt
-    let cfg_attrs = adt
-        .attrs()
-        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
-    for attr in cfg_attrs {
-        impl_.add_attr(attr.clone_for_update());
-    }
+    add_cfg_attrs_to(adt, &impl_);
 
     impl_
 }
 
+pub(crate) fn add_cfg_attrs_to<T, U>(from: &T, to: &U)
+where
+    T: HasAttrs,
+    U: AttrsOwnerEdit,
+{
+    let cfg_attrs =
+        from.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg"));
+    for attr in cfg_attrs {
+        to.add_attr(attr.clone_for_update());
+    }
+}
+
 pub(crate) fn add_method_to_adt(
     builder: &mut SourceChangeBuilder,
     adt: &ast::Adt,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 092219a058a..975c2f02259 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -37,6 +37,7 @@ use ide_db::{
     SymbolKind, documentation::HasDocs, path_transform::PathTransform,
     syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items,
 };
+use syntax::ast::HasGenericParams;
 use syntax::{
     AstNode, SmolStr, SyntaxElement, SyntaxKind, T, TextRange, ToSmolStr,
     ast::{self, HasGenericArgs, HasTypeBounds, edit_in_place::AttrsOwnerEdit, make},
@@ -390,6 +391,12 @@ fn add_type_alias_impl(
             } else if let Some(end) = transformed_ty.eq_token().map(|tok| tok.text_range().start())
             {
                 end
+            } else if let Some(end) = transformed_ty
+                .where_clause()
+                .and_then(|wc| wc.where_token())
+                .map(|tok| tok.text_range().start())
+            {
+                end
             } else if let Some(end) =
                 transformed_ty.semicolon_token().map(|tok| tok.text_range().start())
             {
@@ -400,17 +407,29 @@ fn add_type_alias_impl(
 
             let len = end - start;
             let mut decl = transformed_ty.syntax().text().slice(..len).to_string();
-            if !decl.ends_with(' ') {
-                decl.push(' ');
-            }
-            decl.push_str("= ");
+            decl.truncate(decl.trim_end().len());
+            decl.push_str(" = ");
+
+            let wc = transformed_ty
+                .where_clause()
+                .map(|wc| {
+                    let ws = wc
+                        .where_token()
+                        .and_then(|it| it.prev_token())
+                        .filter(|token| token.kind() == SyntaxKind::WHITESPACE)
+                        .map(|token| token.to_string())
+                        .unwrap_or_else(|| " ".into());
+                    format!("{ws}{wc}")
+                })
+                .unwrap_or_default();
 
             match ctx.config.snippet_cap {
                 Some(cap) => {
-                    let snippet = format!("{decl}$0;");
+                    let snippet = format!("{decl}$0{wc};");
                     item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
                 }
                 None => {
+                    decl.push_str(&wc);
                     item.text_edit(TextEdit::replace(replacement_range, decl));
                 }
             };
@@ -1440,6 +1459,30 @@ impl<'b> Tr<'b> for () {
 "#,
         );
     }
+    #[test]
+    fn includes_where_clause() {
+        check_edit(
+            "type Ty",
+            r#"
+trait Tr {
+    type Ty where Self: Copy;
+}
+
+impl Tr for () {
+    $0
+}
+"#,
+            r#"
+trait Tr {
+    type Ty where Self: Copy;
+}
+
+impl Tr for () {
+    type Ty = $0 where Self: Copy;
+}
+"#,
+        );
+    }
 
     #[test]
     fn strips_comments() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
index 179d6693602..ac32649d4ff 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
@@ -458,6 +458,33 @@ type O = $0;
         r"
 struct A;
 trait B {
+type O<'a>
+where
+Self: 'a;
+}
+impl B for A {
+$0
+}
+",
+        r#"
+struct A;
+trait B {
+type O<'a>
+where
+Self: 'a;
+}
+impl B for A {
+type O<'a> = $0
+where
+Self: 'a;
+}
+"#,
+    );
+    check_edit(
+        "type O",
+        r"
+struct A;
+trait B {
 type O: ?Sized = u32;
 }
 impl B for A {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index de046e70c67..973256c470f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -11,6 +11,40 @@
         },
         [
             FileSymbol {
+                name: "A",
+                def: Variant(
+                    Variant {
+                        id: EnumVariantId(
+                            7800,
+                        ),
+                    },
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: FileId(
+                        EditionedFileId(
+                            Id(2000),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: VARIANT,
+                        range: 201..202,
+                    },
+                    name_ptr: AstPtr(
+                        SyntaxNodePtr {
+                            kind: NAME,
+                            range: 201..202,
+                        },
+                    ),
+                },
+                container_name: Some(
+                    "Enum",
+                ),
+                is_alias: false,
+                is_assoc: true,
+                is_import: false,
+                do_not_complete: Yes,
+            },
+            FileSymbol {
                 name: "Alias",
                 def: TypeAlias(
                     TypeAlias {
@@ -43,6 +77,40 @@
                 do_not_complete: Yes,
             },
             FileSymbol {
+                name: "B",
+                def: Variant(
+                    Variant {
+                        id: EnumVariantId(
+                            7801,
+                        ),
+                    },
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: FileId(
+                        EditionedFileId(
+                            Id(2000),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: VARIANT,
+                        range: 204..205,
+                    },
+                    name_ptr: AstPtr(
+                        SyntaxNodePtr {
+                            kind: NAME,
+                            range: 204..205,
+                        },
+                    ),
+                },
+                container_name: Some(
+                    "Enum",
+                ),
+                is_alias: false,
+                is_assoc: true,
+                is_import: false,
+                do_not_complete: Yes,
+            },
+            FileSymbol {
                 name: "CONST",
                 def: Const(
                     Const {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
index 06f35759420..7402133f747 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -183,4 +183,28 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn generic_assoc_type_infer_lifetime_in_expr_position() {
+        check_diagnostics(
+            r#"
+//- minicore: sized
+struct Player;
+
+struct Foo<'c, C> {
+    _v: &'c C,
+}
+trait WithSignals: Sized {
+    type SignalCollection<'c, C>;
+    fn __signals_from_external(&self) -> Self::SignalCollection<'_, Self>;
+}
+impl WithSignals for Player {
+    type SignalCollection<'c, C> = Foo<'c, C>;
+    fn __signals_from_external(&self) -> Self::SignalCollection<'_, Self> {
+        Self::SignalCollection { _v: self }
+    }
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index d8f6e813d80..17caf630182 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -983,4 +983,19 @@ fn test() {
             "#,
         );
     }
+
+    #[test]
+    fn naked_asm_is_safe() {
+        check_diagnostics(
+            r#"
+#[rustc_builtin_macro]
+macro_rules! naked_asm { () => {} }
+
+#[unsafe(naked)]
+extern "C" fn naked() {
+    naked_asm!("");
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index f58202a4213..a5d9a10d2e5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -505,7 +505,7 @@ fn map_links<'e>(
         Event::End(Tag::Link(link_type, target, _)) => {
             in_link = false;
             Event::End(Tag::Link(
-                end_link_type.unwrap_or(link_type),
+                end_link_type.take().unwrap_or(link_type),
                 end_link_target.take().unwrap_or(target),
                 CowStr::Borrowed(""),
             ))
@@ -514,7 +514,7 @@ fn map_links<'e>(
             let (link_type, link_target_s, link_name) =
                 callback(&end_link_target.take().unwrap(), &s, range, end_link_type.unwrap());
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
-            if !matches!(end_link_type, Some(LinkType::Autolink)) {
+            if !matches!(end_link_type, Some(LinkType::Autolink)) && link_type.is_some() {
                 end_link_type = link_type;
             }
             Event::Text(CowStr::Boxed(link_name.into()))
@@ -523,7 +523,7 @@ fn map_links<'e>(
             let (link_type, link_target_s, link_name) =
                 callback(&end_link_target.take().unwrap(), &s, range, end_link_type.unwrap());
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
-            if !matches!(end_link_type, Some(LinkType::Autolink)) {
+            if !matches!(end_link_type, Some(LinkType::Autolink)) && link_type.is_some() {
                 end_link_type = link_type;
             }
             Event::Code(CowStr::Boxed(link_name.into()))
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index 9bd8504733a..c081796d078 100755
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -23,6 +23,7 @@ pub enum FoldKind {
     WhereClause,
     ReturnType,
     MatchArm,
+    Function,
     // region: item runs
     Modules,
     Consts,
@@ -47,6 +48,7 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
     let mut res = vec![];
     let mut visited_comments = FxHashSet::default();
     let mut visited_nodes = FxHashSet::default();
+    let mut merged_fn_bodies = FxHashSet::default();
 
     // regions can be nested, here is a LIFO buffer
     let mut region_starts: Vec<TextSize> = vec![];
@@ -59,6 +61,32 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
                 NodeOrToken::Token(token) => token.text().contains('\n'),
             };
             if is_multiline {
+                // for the func with multiline param list
+                if matches!(element.kind(), FN) {
+                    if let NodeOrToken::Node(node) = &element {
+                        if let Some(fn_node) = ast::Fn::cast(node.clone()) {
+                            if !fn_node
+                                .param_list()
+                                .map(|param_list| param_list.syntax().text().contains_char('\n'))
+                                .unwrap_or(false)
+                            {
+                                continue;
+                            }
+
+                            if let Some(body) = fn_node.body() {
+                                res.push(Fold {
+                                    range: TextRange::new(
+                                        node.text_range().start(),
+                                        node.text_range().end(),
+                                    ),
+                                    kind: FoldKind::Function,
+                                });
+                                merged_fn_bodies.insert(body.syntax().text_range());
+                                continue;
+                            }
+                        }
+                    }
+                }
                 res.push(Fold { range: element.text_range(), kind });
                 continue;
             }
@@ -152,6 +180,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
         ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList),
         ARRAY_EXPR => Some(FoldKind::Array),
         RET_TYPE => Some(FoldKind::ReturnType),
+        FN => Some(FoldKind::Function),
         WHERE_CLAUSE => Some(FoldKind::WhereClause),
         ASSOC_ITEM_LIST
         | RECORD_FIELD_LIST
@@ -291,6 +320,7 @@ mod tests {
 
     use super::*;
 
+    #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (ranges, text) = extract_tags(ra_fixture, "fold");
 
@@ -322,6 +352,7 @@ mod tests {
                 FoldKind::WhereClause => "whereclause",
                 FoldKind::ReturnType => "returntype",
                 FoldKind::MatchArm => "matcharm",
+                FoldKind::Function => "function",
                 FoldKind::TraitAliases => "traitaliases",
                 FoldKind::ExternCrates => "externcrates",
             };
@@ -330,6 +361,23 @@ mod tests {
     }
 
     #[test]
+    fn test_fold_func_with_multiline_param_list() {
+        check(
+            r#"
+<fold function>fn func<fold arglist>(
+    a: i32,
+    b: i32,
+    c: i32,
+)</fold> <fold block>{
+
+
+
+}</fold></fold>
+"#,
+        );
+    }
+
+    #[test]
     fn test_fold_comments() {
         check(
             r#"
@@ -541,10 +589,10 @@ const _: S = S <fold block>{
     fn fold_multiline_params() {
         check(
             r#"
-fn foo<fold arglist>(
+<fold function>fn foo<fold arglist>(
     x: i32,
     y: String,
-)</fold> {}
+)</fold> {}</fold>
 "#,
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index f63499aa0fd..c5480217a91 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -10958,3 +10958,68 @@ fn bar$0() -> Foo {
         "#]],
     );
 }
+
+#[test]
+fn regression_20190() {
+    check(
+        r#"
+struct Foo;
+
+/// [`foo` bar](Foo).
+fn has_docs$0() {}
+    "#,
+        expect![[r#"
+            *has_docs*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            fn has_docs()
+            ```
+
+            ---
+
+            [`foo` bar](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html).
+        "#]],
+    );
+}
+
+#[test]
+fn regression_20225() {
+    check(
+        r#"
+//- minicore: coerce_unsized
+trait Trait {
+    type Type<'a, T: ?Sized + 'a>;
+}
+
+enum Borrowed {}
+
+impl Trait for Borrowed {
+    type Type<'a, T: ?Sized + 'a> = &'a T;
+}
+
+enum Enum<'a, T: Trait + 'a> {
+    Variant1(T::Type<'a, [Enum<'a, T>]>),
+    Variant2,
+}
+
+impl Enum<'_, Borrowed> {
+    const CONSTANT$0: Self = Self::Variant1(&[Self::Variant2]);
+}
+    "#,
+        expect![[r#"
+            *CONSTANT*
+
+            ```rust
+            ra_test_fixture::Enum
+            ```
+
+            ```rust
+            const CONSTANT: Self = Variant1(&[Variant2])
+            ```
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index bf4688e9d82..d0539abe282 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -92,7 +92,7 @@ pub(super) fn hints(
                 },
                 MirSpan::Unknown => continue,
             };
-            let binding = &hir.bindings[binding_idx];
+            let binding = &hir[binding_idx];
             let name = binding.name.display_no_db(display_target.edition).to_smolstr();
             if name.starts_with("<ra@") {
                 continue; // Ignore desugared variables
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
index cd01c075832..0da1785234a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
@@ -17,8 +17,12 @@ pub(super) fn hints(
     let parent = path.syntax().parent()?;
     let range = match path {
         Either::Left(path) => {
-            let paren =
-                parent.ancestors().take_while(|it| ast::ParenType::can_cast(it.kind())).last();
+            let paren = parent
+                .ancestors()
+                .take_while(|it| {
+                    ast::ParenType::can_cast(it.kind()) || ast::ForType::can_cast(it.kind())
+                })
+                .last();
             let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent);
             if ast::TypeBound::can_cast(parent.kind())
                 || ast::TypeAnchor::can_cast(parent.kind())
@@ -34,7 +38,7 @@ pub(super) fn hints(
                 return None;
             }
             sema.resolve_trait(&path.path()?)?;
-            paren.map_or_else(|| path.syntax().text_range(), |it| it.text_range())
+            path.syntax().text_range()
         }
         Either::Right(dyn_) => {
             if dyn_.dyn_token().is_some() {
@@ -89,7 +93,7 @@ fn foo(_: &T,  _: for<'a> T) {}
 impl T {}
   // ^ dyn
 impl T for (T) {}
-        // ^^^ dyn
+         // ^ dyn
 impl T
 "#,
         );
@@ -112,7 +116,7 @@ fn foo(
     _: &mut (T + T)
     //       ^^^^^ dyn
     _: *mut (T),
-    //      ^^^ dyn
+    //       ^ dyn
 ) {}
 "#,
         );
@@ -136,4 +140,26 @@ fn foo(
             "#]],
         );
     }
+
+    #[test]
+    fn hrtb_bound_does_not_add_dyn() {
+        check(
+            r#"
+//- minicore: fn
+fn test<F>(f: F) where F: for<'a> FnOnce(&'a i32) {}
+     // ^: Sized
+        "#,
+        );
+    }
+
+    #[test]
+    fn with_parentheses() {
+        check(
+            r#"
+trait T {}
+fn foo(v: &(T)) {}
+         // ^ dyn
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index 0ac25da3294..2b4151e3b75 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -4,7 +4,7 @@ use crate::grammar::attributes::ATTRIBUTE_FIRST;
 
 use super::*;
 
-pub(super) use atom::{EXPR_RECOVERY_SET, LITERAL_FIRST, literal};
+pub(super) use atom::{EXPR_RECOVERY_SET, LITERAL_FIRST, literal, parse_asm_expr};
 pub(crate) use atom::{block_expr, match_arm_list};
 
 #[derive(PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 8ed0fc6729f..76656567e7f 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -253,8 +253,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
     let m = p.start();
     p.bump_remap(T![builtin]);
     p.bump(T![#]);
-    if p.at_contextual_kw(T![offset_of]) {
-        p.bump_remap(T![offset_of]);
+    if p.eat_contextual_kw(T![offset_of]) {
         p.expect(T!['(']);
         type_(p);
         p.expect(T![,]);
@@ -278,8 +277,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
             p.expect(T![')']);
         }
         Some(m.complete(p, OFFSET_OF_EXPR))
-    } else if p.at_contextual_kw(T![format_args]) {
-        p.bump_remap(T![format_args]);
+    } else if p.eat_contextual_kw(T![format_args]) {
         p.expect(T!['(']);
         expr(p);
         if p.eat(T![,]) {
@@ -302,7 +300,16 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
         }
         p.expect(T![')']);
         Some(m.complete(p, FORMAT_ARGS_EXPR))
-    } else if p.at_contextual_kw(T![asm]) {
+    } else if p.eat_contextual_kw(T![asm])
+        || p.eat_contextual_kw(T![global_asm])
+        || p.eat_contextual_kw(T![naked_asm])
+    {
+        // test asm_kinds
+        // fn foo() {
+        //     builtin#asm("");
+        //     builtin#global_asm("");
+        //     builtin#naked_asm("");
+        // }
         parse_asm_expr(p, m)
     } else {
         m.abandon(p);
@@ -321,8 +328,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
 //         tmp = out(reg) _,
 //     );
 // }
-fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
-    p.bump_remap(T![asm]);
+pub(crate) fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
     p.expect(T!['(']);
     if expr(p).is_none() {
         p.err_and_bump("expected asm template");
@@ -411,11 +417,10 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
             dir_spec.abandon(p);
             op.abandon(p);
             op_n.abandon(p);
-            p.err_and_bump("expected asm operand");
 
-            // improves error recovery and handles err_and_bump recovering from `{` which gets
-            // the parser stuck here
+            // improves error recovery
             if p.at(T!['{']) {
+                p.error("expected asm operand");
                 // test_err bad_asm_expr
                 // fn foo() {
                 //     builtin#asm(
@@ -423,6 +428,8 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
                 //     );
                 // }
                 expr(p);
+            } else {
+                p.err_and_bump("expected asm operand");
             }
 
             if p.at(T!['}']) {
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
index b9f4866574a..8e551b0b961 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
@@ -261,6 +261,19 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke
         T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
         T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m),
 
+        IDENT
+            if p.at_contextual_kw(T![builtin])
+                && p.nth_at(1, T![#])
+                && p.nth_at_contextual_kw(2, T![global_asm]) =>
+        {
+            p.bump_remap(T![builtin]);
+            p.bump(T![#]);
+            p.bump_remap(T![global_asm]);
+            // test global_asm
+            // builtin#global_asm("")
+            expressions::parse_asm_expr(p, m);
+        }
+
         _ => return Err(m),
     };
     Ok(())
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index bff9acd78fa..8fff1c3db74 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -11,8 +11,8 @@
 use std::ops;
 
 use rustc_literal_escaper::{
-    unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str, EscapeError,
-    Mode,
+    EscapeError, Mode, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char,
+    unescape_str,
 };
 
 use crate::{
diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs
index 36a363afe93..ca02d9fdfde 100644
--- a/src/tools/rust-analyzer/crates/parser/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs
@@ -29,7 +29,7 @@ pub(crate) struct Parser<'t> {
     edition: Edition,
 }
 
-const PARSER_STEP_LIMIT: usize = 15_000_000;
+const PARSER_STEP_LIMIT: usize = if cfg!(debug_assertions) { 150_000 } else { 15_000_000 };
 
 impl<'t> Parser<'t> {
     pub(super) fn new(inp: &'t Input, edition: Edition) -> Parser<'t> {
@@ -254,7 +254,10 @@ impl<'t> Parser<'t> {
 
     /// Create an error node and consume the next token.
     pub(crate) fn err_and_bump(&mut self, message: &str) {
-        self.err_recover(message, TokenSet::EMPTY);
+        let m = self.start();
+        self.error(message);
+        self.bump_any();
+        m.complete(self, ERROR);
     }
 
     /// Create an error node and consume the next token unless it is in the recovery set.
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index f534546ea07..12a13caa4d9 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -120,12 +120,14 @@ pub enum SyntaxKind {
     DYN_KW,
     FORMAT_ARGS_KW,
     GEN_KW,
+    GLOBAL_ASM_KW,
     INLATEOUT_KW,
     INOUT_KW,
     LABEL_KW,
     LATEOUT_KW,
     MACRO_RULES_KW,
     MAY_UNWIND_KW,
+    NAKED_ASM_KW,
     NOMEM_KW,
     NORETURN_KW,
     NOSTACK_KW,
@@ -599,12 +601,14 @@ impl SyntaxKind {
             DEFAULT_KW => "default",
             DYN_KW => "dyn",
             FORMAT_ARGS_KW => "format_args",
+            GLOBAL_ASM_KW => "global_asm",
             INLATEOUT_KW => "inlateout",
             INOUT_KW => "inout",
             LABEL_KW => "label",
             LATEOUT_KW => "lateout",
             MACRO_RULES_KW => "macro_rules",
             MAY_UNWIND_KW => "may_unwind",
+            NAKED_ASM_KW => "naked_asm",
             NOMEM_KW => "nomem",
             NORETURN_KW => "noreturn",
             NOSTACK_KW => "nostack",
@@ -699,12 +703,14 @@ impl SyntaxKind {
             DEFAULT_KW => true,
             DYN_KW if edition < Edition::Edition2018 => true,
             FORMAT_ARGS_KW => true,
+            GLOBAL_ASM_KW => true,
             INLATEOUT_KW => true,
             INOUT_KW => true,
             LABEL_KW => true,
             LATEOUT_KW => true,
             MACRO_RULES_KW => true,
             MAY_UNWIND_KW => true,
+            NAKED_ASM_KW => true,
             NOMEM_KW => true,
             NORETURN_KW => true,
             NOSTACK_KW => true,
@@ -787,12 +793,14 @@ impl SyntaxKind {
             DEFAULT_KW => true,
             DYN_KW if edition < Edition::Edition2018 => true,
             FORMAT_ARGS_KW => true,
+            GLOBAL_ASM_KW => true,
             INLATEOUT_KW => true,
             INOUT_KW => true,
             LABEL_KW => true,
             LATEOUT_KW => true,
             MACRO_RULES_KW => true,
             MAY_UNWIND_KW => true,
+            NAKED_ASM_KW => true,
             NOMEM_KW => true,
             NORETURN_KW => true,
             NOSTACK_KW => true,
@@ -938,12 +946,14 @@ impl SyntaxKind {
             "default" => DEFAULT_KW,
             "dyn" if edition < Edition::Edition2018 => DYN_KW,
             "format_args" => FORMAT_ARGS_KW,
+            "global_asm" => GLOBAL_ASM_KW,
             "inlateout" => INLATEOUT_KW,
             "inout" => INOUT_KW,
             "label" => LABEL_KW,
             "lateout" => LATEOUT_KW,
             "macro_rules" => MACRO_RULES_KW,
             "may_unwind" => MAY_UNWIND_KW,
+            "naked_asm" => NAKED_ASM_KW,
             "nomem" => NOMEM_KW,
             "noreturn" => NORETURN_KW,
             "nostack" => NOSTACK_KW,
@@ -998,7 +1008,7 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; [frontmatter] => { $ crate :: SyntaxKind :: FRONTMATTER } ; }
+macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [global_asm] => { $ crate :: SyntaxKind :: GLOBAL_ASM_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [naked_asm] => { $ crate :: SyntaxKind :: NAKED_ASM_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; [frontmatter] => { $ crate :: SyntaxKind :: FRONTMATTER } ; }
 impl ::core::marker::Copy for SyntaxKind {}
 impl ::core::clone::Clone for SyntaxKind {
     #[inline]
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 6ec4192830b..cef7b0ee239 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -21,6 +21,8 @@ mod ok {
     #[test]
     fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); }
     #[test]
+    fn asm_kinds() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_kinds.rs"); }
+    #[test]
     fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); }
     #[test]
     fn assoc_const_eq() {
@@ -298,6 +300,8 @@ mod ok {
         run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_list.rs");
     }
     #[test]
+    fn global_asm() { run_and_expect_no_errors("test_data/parser/inline/ok/global_asm.rs"); }
+    #[test]
     fn half_open_range_pat() {
         run_and_expect_no_errors("test_data/parser/inline/ok/half_open_range_pat.rs");
     }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rast
new file mode 100644
index 00000000000..c337d89aa50
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rast
@@ -0,0 +1,48 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          ASM_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            ASM_KW "asm"
+            L_PAREN "("
+            LITERAL
+              STRING "\"\""
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n    "
+        ASM_EXPR
+          BUILTIN_KW "builtin"
+          POUND "#"
+          GLOBAL_ASM_KW "global_asm"
+          L_PAREN "("
+          LITERAL
+            STRING "\"\""
+          R_PAREN ")"
+        SEMICOLON ";"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          ASM_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            NAKED_ASM_KW "naked_asm"
+            L_PAREN "("
+            LITERAL
+              STRING "\"\""
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rs
new file mode 100644
index 00000000000..9c03e9de689
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_kinds.rs
@@ -0,0 +1,5 @@
+fn foo() {
+    builtin#asm("");
+    builtin#global_asm("");
+    builtin#naked_asm("");
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rast
new file mode 100644
index 00000000000..5337c56be17
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rast
@@ -0,0 +1,10 @@
+SOURCE_FILE
+  ASM_EXPR
+    BUILTIN_KW "builtin"
+    POUND "#"
+    GLOBAL_ASM_KW "global_asm"
+    L_PAREN "("
+    LITERAL
+      STRING "\"\""
+    R_PAREN ")"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rs
new file mode 100644
index 00000000000..967ce1f5fd9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rs
@@ -0,0 +1 @@
+builtin#global_asm("")
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs
new file mode 100644
index 00000000000..7966f74df30
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs
@@ -0,0 +1,34 @@
+//! Read `.cargo/config.toml` as a JSON object
+use rustc_hash::FxHashMap;
+use toolchain::Tool;
+
+use crate::{ManifestPath, Sysroot, utf8_stdout};
+
+pub(crate) type CargoConfigFile = serde_json::Map<String, serde_json::Value>;
+
+pub(crate) fn read(
+    manifest: &ManifestPath,
+    extra_env: &FxHashMap<String, Option<String>>,
+    sysroot: &Sysroot,
+) -> Option<CargoConfigFile> {
+    let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
+    cargo_config
+        .args(["-Z", "unstable-options", "config", "get", "--format", "json"])
+        .env("RUSTC_BOOTSTRAP", "1");
+    if manifest.is_rust_manifest() {
+        cargo_config.arg("-Zscript");
+    }
+
+    tracing::debug!("Discovering cargo config by {:?}", cargo_config);
+    let json: serde_json::Map<String, serde_json::Value> = utf8_stdout(&mut cargo_config)
+        .inspect(|json| {
+            tracing::debug!("Discovered cargo config: {:?}", json);
+        })
+        .inspect_err(|err| {
+            tracing::debug!("Failed to discover cargo config: {:?}", err);
+        })
+        .ok()
+        .and_then(|stdout| serde_json::from_str(&stdout).ok())?;
+
+    Some(json)
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 4bacc904174..daadcd9d79a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -300,8 +300,6 @@ pub struct CargoMetadataConfig {
     pub extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
-    /// The target dir for this workspace load.
-    pub target_dir: Utf8PathBuf,
     /// What kind of metadata are we fetching: workspace, rustc, or sysroot.
     pub kind: &'static str,
     /// The toolchain version, if known.
@@ -317,188 +315,6 @@ struct PackageMetadata {
 }
 
 impl CargoWorkspace {
-    /// Fetches the metadata for the given `cargo_toml` manifest.
-    /// A successful result may contain another metadata error if the initial fetching failed but
-    /// the `--no-deps` retry succeeded.
-    ///
-    /// The sysroot is used to set the `RUSTUP_TOOLCHAIN` env var when invoking cargo
-    /// to ensure that the rustup proxy uses the correct toolchain.
-    pub fn fetch_metadata(
-        cargo_toml: &ManifestPath,
-        current_dir: &AbsPath,
-        config: &CargoMetadataConfig,
-        sysroot: &Sysroot,
-        no_deps: bool,
-        locked: bool,
-        progress: &dyn Fn(String),
-    ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
-        let res = Self::fetch_metadata_(
-            cargo_toml,
-            current_dir,
-            config,
-            sysroot,
-            no_deps,
-            locked,
-            progress,
-        );
-        if let Ok((_, Some(ref e))) = res {
-            tracing::warn!(
-                %cargo_toml,
-                ?e,
-                "`cargo metadata` failed, but retry with `--no-deps` succeeded"
-            );
-        }
-        res
-    }
-
-    fn fetch_metadata_(
-        cargo_toml: &ManifestPath,
-        current_dir: &AbsPath,
-        config: &CargoMetadataConfig,
-        sysroot: &Sysroot,
-        no_deps: bool,
-        locked: bool,
-        progress: &dyn Fn(String),
-    ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
-        let cargo = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env);
-        let mut meta = MetadataCommand::new();
-        meta.cargo_path(cargo.get_program());
-        cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default()));
-        meta.manifest_path(cargo_toml.to_path_buf());
-        match &config.features {
-            CargoFeatures::All => {
-                meta.features(CargoOpt::AllFeatures);
-            }
-            CargoFeatures::Selected { features, no_default_features } => {
-                if *no_default_features {
-                    meta.features(CargoOpt::NoDefaultFeatures);
-                }
-                if !features.is_empty() {
-                    meta.features(CargoOpt::SomeFeatures(features.clone()));
-                }
-            }
-        }
-        meta.current_dir(current_dir);
-
-        let mut other_options = vec![];
-        // cargo metadata only supports a subset of flags of what cargo usually accepts, and usually
-        // the only relevant flags for metadata here are unstable ones, so we pass those along
-        // but nothing else
-        let mut extra_args = config.extra_args.iter();
-        while let Some(arg) = extra_args.next() {
-            if arg == "-Z" {
-                if let Some(arg) = extra_args.next() {
-                    other_options.push("-Z".to_owned());
-                    other_options.push(arg.to_owned());
-                }
-            }
-        }
-
-        if !config.targets.is_empty() {
-            other_options.extend(
-                config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
-            );
-        }
-        if no_deps {
-            other_options.push("--no-deps".to_owned());
-        }
-
-        let mut using_lockfile_copy = false;
-        // The manifest is a rust file, so this means its a script manifest
-        if cargo_toml.is_rust_manifest() {
-            other_options.push("-Zscript".to_owned());
-        } else if config
-            .toolchain_version
-            .as_ref()
-            .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH)
-        {
-            let lockfile = <_ as AsRef<Utf8Path>>::as_ref(cargo_toml).with_extension("lock");
-            let target_lockfile = config
-                .target_dir
-                .join("rust-analyzer")
-                .join("metadata")
-                .join(config.kind)
-                .join("Cargo.lock");
-            match std::fs::copy(&lockfile, &target_lockfile) {
-                Ok(_) => {
-                    using_lockfile_copy = true;
-                    other_options.push("--lockfile-path".to_owned());
-                    other_options.push(target_lockfile.to_string());
-                }
-                Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
-                    // There exists no lockfile yet
-                    using_lockfile_copy = true;
-                    other_options.push("--lockfile-path".to_owned());
-                    other_options.push(target_lockfile.to_string());
-                }
-                Err(e) => {
-                    tracing::warn!(
-                        "Failed to copy lock file from `{lockfile}` to `{target_lockfile}`: {e}",
-                    );
-                }
-            }
-        }
-        if using_lockfile_copy {
-            other_options.push("-Zunstable-options".to_owned());
-            meta.env("RUSTC_BOOTSTRAP", "1");
-        }
-        // No need to lock it if we copied the lockfile, we won't modify the original after all/
-        // This way cargo cannot error out on us if the lockfile requires updating.
-        if !using_lockfile_copy && locked {
-            other_options.push("--locked".to_owned());
-        }
-        meta.other_options(other_options);
-
-        // FIXME: Fetching metadata is a slow process, as it might require
-        // calling crates.io. We should be reporting progress here, but it's
-        // unclear whether cargo itself supports it.
-        progress("cargo metadata: started".to_owned());
-
-        let res = (|| -> anyhow::Result<(_, _)> {
-            let mut errored = false;
-            let output =
-                spawn_with_streaming_output(meta.cargo_command(), &mut |_| (), &mut |line| {
-                    errored = errored || line.starts_with("error") || line.starts_with("warning");
-                    if errored {
-                        progress("cargo metadata: ?".to_owned());
-                        return;
-                    }
-                    progress(format!("cargo metadata: {line}"));
-                })?;
-            if !output.status.success() {
-                progress(format!("cargo metadata: failed {}", output.status));
-                let error = cargo_metadata::Error::CargoMetadata {
-                    stderr: String::from_utf8(output.stderr)?,
-                }
-                .into();
-                if !no_deps {
-                    // If we failed to fetch metadata with deps, try again without them.
-                    // This makes r-a still work partially when offline.
-                    if let Ok((metadata, _)) = Self::fetch_metadata_(
-                        cargo_toml,
-                        current_dir,
-                        config,
-                        sysroot,
-                        true,
-                        locked,
-                        progress,
-                    ) {
-                        return Ok((metadata, Some(error)));
-                    }
-                }
-                return Err(error);
-            }
-            let stdout = from_utf8(&output.stdout)?
-                .lines()
-                .find(|line| line.starts_with('{'))
-                .ok_or(cargo_metadata::Error::NoJson)?;
-            Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None))
-        })()
-        .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()));
-        progress("cargo metadata: finished".to_owned());
-        res
-    }
-
     pub fn new(
         mut meta: cargo_metadata::Metadata,
         ws_manifest_path: ManifestPath,
@@ -733,3 +549,214 @@ impl CargoWorkspace {
         self.requires_rustc_private
     }
 }
+
+pub(crate) struct FetchMetadata {
+    command: cargo_metadata::MetadataCommand,
+    lockfile_path: Option<Utf8PathBuf>,
+    kind: &'static str,
+    no_deps: bool,
+    no_deps_result: anyhow::Result<cargo_metadata::Metadata>,
+    other_options: Vec<String>,
+}
+
+impl FetchMetadata {
+    /// Builds a command to fetch metadata for the given `cargo_toml` manifest.
+    ///
+    /// Performs a lightweight pre-fetch using the `--no-deps` option,
+    /// available via [`FetchMetadata::no_deps_metadata`], to gather basic
+    /// information such as the `target-dir`.
+    ///
+    /// The provided sysroot is used to set the `RUSTUP_TOOLCHAIN`
+    /// environment variable when invoking Cargo, ensuring that the
+    /// rustup proxy selects the correct toolchain.
+    pub(crate) fn new(
+        cargo_toml: &ManifestPath,
+        current_dir: &AbsPath,
+        config: &CargoMetadataConfig,
+        sysroot: &Sysroot,
+        no_deps: bool,
+    ) -> Self {
+        let cargo = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env);
+        let mut command = MetadataCommand::new();
+        command.cargo_path(cargo.get_program());
+        cargo.get_envs().for_each(|(var, val)| _ = command.env(var, val.unwrap_or_default()));
+        command.manifest_path(cargo_toml.to_path_buf());
+        match &config.features {
+            CargoFeatures::All => {
+                command.features(CargoOpt::AllFeatures);
+            }
+            CargoFeatures::Selected { features, no_default_features } => {
+                if *no_default_features {
+                    command.features(CargoOpt::NoDefaultFeatures);
+                }
+                if !features.is_empty() {
+                    command.features(CargoOpt::SomeFeatures(features.clone()));
+                }
+            }
+        }
+        command.current_dir(current_dir);
+
+        let mut needs_nightly = false;
+        let mut other_options = vec![];
+        // cargo metadata only supports a subset of flags of what cargo usually accepts, and usually
+        // the only relevant flags for metadata here are unstable ones, so we pass those along
+        // but nothing else
+        let mut extra_args = config.extra_args.iter();
+        while let Some(arg) = extra_args.next() {
+            if arg == "-Z" {
+                if let Some(arg) = extra_args.next() {
+                    needs_nightly = true;
+                    other_options.push("-Z".to_owned());
+                    other_options.push(arg.to_owned());
+                }
+            }
+        }
+
+        let mut lockfile_path = None;
+        if cargo_toml.is_rust_manifest() {
+            needs_nightly = true;
+            other_options.push("-Zscript".to_owned());
+        } else if config
+            .toolchain_version
+            .as_ref()
+            .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH)
+        {
+            lockfile_path = Some(<_ as AsRef<Utf8Path>>::as_ref(cargo_toml).with_extension("lock"));
+        }
+
+        if !config.targets.is_empty() {
+            other_options.extend(
+                config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
+            );
+        }
+
+        command.other_options(other_options.clone());
+
+        if needs_nightly {
+            command.env("RUSTC_BOOTSTRAP", "1");
+        }
+
+        // Pre-fetch basic metadata using `--no-deps`, which:
+        // - avoids fetching registries like crates.io,
+        // - skips dependency resolution and does not modify lockfiles,
+        // - and thus doesn't require progress reporting or copying lockfiles.
+        //
+        // Useful as a fast fallback to extract info like `target-dir`.
+        let cargo_command;
+        let no_deps_result = if no_deps {
+            command.no_deps();
+            cargo_command = command.cargo_command();
+            command.exec()
+        } else {
+            let mut no_deps_command = command.clone();
+            no_deps_command.no_deps();
+            cargo_command = no_deps_command.cargo_command();
+            no_deps_command.exec()
+        }
+        .with_context(|| format!("Failed to run `{cargo_command:?}`"));
+
+        Self { command, lockfile_path, kind: config.kind, no_deps, no_deps_result, other_options }
+    }
+
+    pub(crate) fn no_deps_metadata(&self) -> Option<&cargo_metadata::Metadata> {
+        self.no_deps_result.as_ref().ok()
+    }
+
+    /// Executes the metadata-fetching command.
+    ///
+    /// A successful result may still contain a metadata error if the full fetch failed,
+    /// but the fallback `--no-deps` pre-fetch succeeded during command construction.
+    pub(crate) fn exec(
+        self,
+        target_dir: &Utf8Path,
+        locked: bool,
+        progress: &dyn Fn(String),
+    ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
+        let Self { mut command, lockfile_path, kind, no_deps, no_deps_result, mut other_options } =
+            self;
+
+        if no_deps {
+            return no_deps_result.map(|m| (m, None));
+        }
+
+        let mut using_lockfile_copy = false;
+        // The manifest is a rust file, so this means its a script manifest
+        if let Some(lockfile) = lockfile_path {
+            let target_lockfile =
+                target_dir.join("rust-analyzer").join("metadata").join(kind).join("Cargo.lock");
+            match std::fs::copy(&lockfile, &target_lockfile) {
+                Ok(_) => {
+                    using_lockfile_copy = true;
+                    other_options.push("--lockfile-path".to_owned());
+                    other_options.push(target_lockfile.to_string());
+                }
+                Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
+                    // There exists no lockfile yet
+                    using_lockfile_copy = true;
+                    other_options.push("--lockfile-path".to_owned());
+                    other_options.push(target_lockfile.to_string());
+                }
+                Err(e) => {
+                    tracing::warn!(
+                        "Failed to copy lock file from `{lockfile}` to `{target_lockfile}`: {e}",
+                    );
+                }
+            }
+        }
+        if using_lockfile_copy {
+            other_options.push("-Zunstable-options".to_owned());
+            command.env("RUSTC_BOOTSTRAP", "1");
+        }
+        // No need to lock it if we copied the lockfile, we won't modify the original after all/
+        // This way cargo cannot error out on us if the lockfile requires updating.
+        if !using_lockfile_copy && locked {
+            other_options.push("--locked".to_owned());
+        }
+        command.other_options(other_options);
+
+        // FIXME: Fetching metadata is a slow process, as it might require
+        // calling crates.io. We should be reporting progress here, but it's
+        // unclear whether cargo itself supports it.
+        progress("cargo metadata: started".to_owned());
+
+        let res = (|| -> anyhow::Result<(_, _)> {
+            let mut errored = false;
+            let output =
+                spawn_with_streaming_output(command.cargo_command(), &mut |_| (), &mut |line| {
+                    errored = errored || line.starts_with("error") || line.starts_with("warning");
+                    if errored {
+                        progress("cargo metadata: ?".to_owned());
+                        return;
+                    }
+                    progress(format!("cargo metadata: {line}"));
+                })?;
+            if !output.status.success() {
+                progress(format!("cargo metadata: failed {}", output.status));
+                let error = cargo_metadata::Error::CargoMetadata {
+                    stderr: String::from_utf8(output.stderr)?,
+                }
+                .into();
+                if !no_deps {
+                    // If we failed to fetch metadata with deps, return pre-fetched result without them.
+                    // This makes r-a still work partially when offline.
+                    if let Ok(metadata) = no_deps_result {
+                        tracing::warn!(
+                            ?error,
+                            "`cargo metadata` failed and returning succeeded result with `--no-deps`"
+                        );
+                        return Ok((metadata, Some(error)));
+                    }
+                }
+                return Err(error);
+            }
+            let stdout = from_utf8(&output.stdout)?
+                .lines()
+                .find(|line| line.starts_with('{'))
+                .ok_or(cargo_metadata::Error::NoJson)?;
+            Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None))
+        })()
+        .with_context(|| format!("Failed to run `{:?}`", command.cargo_command()));
+        progress("cargo metadata: finished".to_owned());
+        res
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index 9e0415c3b39..d281492fc98 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -1,10 +1,9 @@
 //! Cargo-like environment variables injection.
 use base_db::Env;
-use paths::{Utf8Path, Utf8PathBuf};
-use rustc_hash::FxHashMap;
+use paths::Utf8Path;
 use toolchain::Tool;
 
-use crate::{ManifestPath, PackageData, Sysroot, TargetKind, utf8_stdout};
+use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile};
 
 /// Recreates the compile-time environment variables that Cargo sets.
 ///
@@ -61,104 +60,68 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe
     env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_"));
 }
 
-pub(crate) fn cargo_config_env(
-    manifest: &ManifestPath,
-    extra_env: &FxHashMap<String, Option<String>>,
-    sysroot: &Sysroot,
-) -> Env {
-    let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
-    cargo_config
-        .args(["-Z", "unstable-options", "config", "get", "env"])
-        .env("RUSTC_BOOTSTRAP", "1");
-    if manifest.is_rust_manifest() {
-        cargo_config.arg("-Zscript");
-    }
-    // if successful we receive `env.key.value = "value" per entry
-    tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
-    utf8_stdout(&mut cargo_config)
-        .map(|stdout| parse_output_cargo_config_env(manifest, &stdout))
-        .inspect(|env| {
-            tracing::debug!("Discovered cargo config env: {:?}", env);
-        })
-        .inspect_err(|err| {
-            tracing::debug!("Failed to discover cargo config env: {:?}", err);
-        })
-        .unwrap_or_default()
-}
-
-fn parse_output_cargo_config_env(manifest: &ManifestPath, stdout: &str) -> Env {
+pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option<CargoConfigFile>) -> Env {
     let mut env = Env::default();
-    let mut relatives = vec![];
-    for (key, val) in
-        stdout.lines().filter_map(|l| l.strip_prefix("env.")).filter_map(|l| l.split_once(" = "))
-    {
-        let val = val.trim_matches('"').to_owned();
-        if let Some((key, modifier)) = key.split_once('.') {
-            match modifier {
-                "relative" => relatives.push((key, val)),
-                "value" => _ = env.insert(key, val),
-                _ => {
-                    tracing::warn!(
-                        "Unknown modifier in cargo config env: {}, expected `relative` or `value`",
-                        modifier
-                    );
-                    continue;
-                }
-            }
-        } else {
-            env.insert(key, val);
-        }
-    }
+    let Some(serde_json::Value::Object(env_json)) = config.as_ref().and_then(|c| c.get("env"))
+    else {
+        return env;
+    };
+
     // FIXME: The base here should be the parent of the `.cargo/config` file, not the manifest.
     // But cargo does not provide this information.
     let base = <_ as AsRef<Utf8Path>>::as_ref(manifest.parent());
-    for (key, relative) in relatives {
-        if relative != "true" {
+
+    for (key, entry) in env_json {
+        let serde_json::Value::Object(entry) = entry else {
             continue;
-        }
-        if let Some(suffix) = env.get(key) {
-            env.insert(key, base.join(suffix).to_string());
-        }
-    }
-    env
-}
+        };
+        let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
+            continue;
+        };
 
-pub(crate) fn cargo_config_build_target_dir(
-    manifest: &ManifestPath,
-    extra_env: &FxHashMap<String, Option<String>>,
-    sysroot: &Sysroot,
-) -> Option<Utf8PathBuf> {
-    let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
-    cargo_config
-        .args(["-Z", "unstable-options", "config", "get", "build.target-dir"])
-        .env("RUSTC_BOOTSTRAP", "1");
-    if manifest.is_rust_manifest() {
-        cargo_config.arg("-Zscript");
+        let value = if entry
+            .get("relative")
+            .and_then(|v| v.as_bool())
+            .is_some_and(std::convert::identity)
+        {
+            base.join(value).to_string()
+        } else {
+            value.to_owned()
+        };
+        env.insert(key, value);
     }
-    utf8_stdout(&mut cargo_config)
-        .map(|stdout| {
-            Utf8Path::new(stdout.trim_start_matches("build.target-dir = ").trim_matches('"'))
-                .to_owned()
-        })
-        .ok()
+
+    env
 }
 
 #[test]
 fn parse_output_cargo_config_env_works() {
-    let stdout = r#"
-env.CARGO_WORKSPACE_DIR.relative = true
-env.CARGO_WORKSPACE_DIR.value = ""
-env.RELATIVE.relative = true
-env.RELATIVE.value = "../relative"
-env.INVALID.relative = invalidbool
-env.INVALID.value = "../relative"
-env.TEST.value = "test"
-"#
-    .trim();
+    let raw = r#"
+{
+  "env": {
+    "CARGO_WORKSPACE_DIR": {
+      "relative": true,
+      "value": ""
+    },
+    "INVALID": {
+      "relative": "invalidbool",
+      "value": "../relative"
+    },
+    "RELATIVE": {
+      "relative": true,
+      "value": "../relative"
+    },
+    "TEST": {
+      "value": "test"
+    }
+  }
+}
+"#;
+    let config: CargoConfigFile = serde_json::from_str(raw).unwrap();
     let cwd = paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap();
     let manifest = paths::AbsPathBuf::assert(cwd.join("Cargo.toml"));
     let manifest = ManifestPath::try_from(manifest).unwrap();
-    let env = parse_output_cargo_config_env(&manifest, stdout);
+    let env = cargo_config_env(&manifest, &Some(config));
     assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
     assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
     assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 436af64cf13..3bf3d06e6b1 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -24,7 +24,7 @@ pub mod toolchain_info {
 
     use std::path::Path;
 
-    use crate::{ManifestPath, Sysroot};
+    use crate::{ManifestPath, Sysroot, cargo_config_file::CargoConfigFile};
 
     #[derive(Copy, Clone)]
     pub enum QueryConfig<'a> {
@@ -32,11 +32,12 @@ pub mod toolchain_info {
         Rustc(&'a Sysroot, &'a Path),
         /// Attempt to use cargo to query the desired information, honoring cargo configurations.
         /// If this fails, falls back to invoking `rustc` directly.
-        Cargo(&'a Sysroot, &'a ManifestPath),
+        Cargo(&'a Sysroot, &'a ManifestPath, &'a Option<CargoConfigFile>),
     }
 }
 
 mod build_dependencies;
+mod cargo_config_file;
 mod cargo_workspace;
 mod env;
 mod manifest_path;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 9f19260d309..9781c46737d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -9,14 +9,15 @@ use std::{env, fs, ops::Not, path::Path, process::Command};
 
 use anyhow::{Result, format_err};
 use itertools::Itertools;
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use stdx::format_to;
 use toolchain::{Tool, probe_for_binary};
 
 use crate::{
     CargoWorkspace, ManifestPath, ProjectJson, RustSourceWorkspaceConfig,
-    cargo_workspace::CargoMetadataConfig, utf8_stdout,
+    cargo_workspace::{CargoMetadataConfig, FetchMetadata},
+    utf8_stdout,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -211,6 +212,7 @@ impl Sysroot {
         sysroot_source_config: &RustSourceWorkspaceConfig,
         no_deps: bool,
         current_dir: &AbsPath,
+        target_dir: &Utf8Path,
         progress: &dyn Fn(String),
     ) -> Option<RustLibSrcWorkspace> {
         assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
@@ -224,6 +226,7 @@ impl Sysroot {
                 match self.load_library_via_cargo(
                     &library_manifest,
                     current_dir,
+                    target_dir,
                     cargo_config,
                     no_deps,
                     progress,
@@ -319,6 +322,7 @@ impl Sysroot {
         &self,
         library_manifest: &ManifestPath,
         current_dir: &AbsPath,
+        target_dir: &Utf8Path,
         cargo_config: &CargoMetadataConfig,
         no_deps: bool,
         progress: &dyn Fn(String),
@@ -331,16 +335,11 @@ impl Sysroot {
             Some("nightly".to_owned()),
         );
 
-        let (mut res, _) = CargoWorkspace::fetch_metadata(
-            library_manifest,
-            current_dir,
-            &cargo_config,
-            self,
-            no_deps,
-            // Make sure we never attempt to write to the sysroot
-            true,
-            progress,
-        )?;
+        // Make sure we never attempt to write to the sysroot
+        let locked = true;
+        let (mut res, _) =
+            FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
+                .exec(target_dir, locked, progress)?;
 
         // Patch out `rustc-std-workspace-*` crates to point to the real crates.
         // This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing.
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index f229e9a650d..ed72520f40d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -239,8 +239,13 @@ fn smoke_test_real_sysroot_cargo() {
     );
     let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo"));
     std::fs::create_dir_all(&cwd).unwrap();
-    let loaded_sysroot =
-        sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), false, &cwd, &|_| ());
+    let loaded_sysroot = sysroot.load_workspace(
+        &RustSourceWorkspaceConfig::default_cargo(),
+        false,
+        &cwd,
+        &Utf8PathBuf::default(),
+        &|_| (),
+    );
     if let Some(loaded_sysroot) = loaded_sysroot {
         sysroot.set_workspace(loaded_sysroot);
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
index a77f76797fc..6e06e88bf7a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -63,7 +63,7 @@ fn rustc_print_cfg(
 ) -> anyhow::Result<String> {
     const RUSTC_ARGS: [&str; 2] = ["--print", "cfg"];
     let (sysroot, current_dir) = match config {
-        QueryConfig::Cargo(sysroot, cargo_toml) => {
+        QueryConfig::Cargo(sysroot, cargo_toml, _) => {
             let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
             cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS);
             if let Some(target) = target {
@@ -109,7 +109,7 @@ mod tests {
         let sysroot = Sysroot::empty();
         let manifest_path =
             ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
-        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path);
+        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
         assert_ne!(get(cfg, None, &FxHashMap::default()), vec![]);
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs
index a4d0ec69537..a28f468e692 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_data_layout.rs
@@ -20,7 +20,7 @@ pub fn get(
             })
     };
     let (sysroot, current_dir) = match config {
-        QueryConfig::Cargo(sysroot, cargo_toml) => {
+        QueryConfig::Cargo(sysroot, cargo_toml, _) => {
             let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
             cmd.env("RUSTC_BOOTSTRAP", "1");
             cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS).args([
@@ -66,7 +66,7 @@ mod tests {
         let sysroot = Sysroot::empty();
         let manifest_path =
             ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
-        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path);
+        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
         assert!(get(cfg, None, &FxHashMap::default()).is_ok());
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_tuple.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_tuple.rs
index f6ab8532197..9f12ededb61 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_tuple.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/target_tuple.rs
@@ -5,7 +5,9 @@ use anyhow::Context;
 use rustc_hash::FxHashMap;
 use toolchain::Tool;
 
-use crate::{ManifestPath, Sysroot, toolchain_info::QueryConfig, utf8_stdout};
+use crate::{
+    Sysroot, cargo_config_file::CargoConfigFile, toolchain_info::QueryConfig, utf8_stdout,
+};
 
 /// For cargo, runs `cargo -Zunstable-options config get build.target` to get the configured project target(s).
 /// For rustc, runs `rustc --print -vV` to get the host target.
@@ -20,8 +22,8 @@ pub fn get(
     }
 
     let (sysroot, current_dir) = match config {
-        QueryConfig::Cargo(sysroot, cargo_toml) => {
-            match cargo_config_build_target(cargo_toml, extra_env, sysroot) {
+        QueryConfig::Cargo(sysroot, cargo_toml, config_file) => {
+            match config_file.as_ref().and_then(cargo_config_build_target) {
                 Some(it) => return Ok(it),
                 None => (sysroot, cargo_toml.parent().as_ref()),
             }
@@ -50,30 +52,30 @@ fn rustc_discover_host_tuple(
     }
 }
 
-fn cargo_config_build_target(
-    cargo_toml: &ManifestPath,
-    extra_env: &FxHashMap<String, Option<String>>,
-    sysroot: &Sysroot,
-) -> Option<Vec<String>> {
-    let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env);
-    cmd.current_dir(cargo_toml.parent()).env("RUSTC_BOOTSTRAP", "1");
-    cmd.args(["-Z", "unstable-options", "config", "get", "build.target"]);
-    // if successful we receive `build.target = "target-tuple"`
-    // or `build.target = ["<target 1>", ..]`
-    // this might be `error: config value `build.target` is not set` in which case we
-    // don't wanna log the error
-    utf8_stdout(&mut cmd).and_then(parse_output_cargo_config_build_target).ok()
+fn cargo_config_build_target(config: &CargoConfigFile) -> Option<Vec<String>> {
+    match parse_json_cargo_config_build_target(config) {
+        Ok(v) => v,
+        Err(e) => {
+            tracing::debug!("Failed to discover cargo config build target {e:?}");
+            None
+        }
+    }
 }
 
 // Parses `"build.target = [target-tuple, target-tuple, ...]"` or `"build.target = "target-tuple"`
-fn parse_output_cargo_config_build_target(stdout: String) -> anyhow::Result<Vec<String>> {
-    let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
-
-    if !trimmed.starts_with('[') {
-        return Ok([trimmed.to_owned()].to_vec());
+fn parse_json_cargo_config_build_target(
+    config: &CargoConfigFile,
+) -> anyhow::Result<Option<Vec<String>>> {
+    let target = config.get("build").and_then(|v| v.as_object()).and_then(|m| m.get("target"));
+    match target {
+        Some(serde_json::Value::String(s)) => Ok(Some(vec![s.to_owned()])),
+        Some(v) => serde_json::from_value(v.clone())
+            .map(Option::Some)
+            .context("Failed to parse `build.target` as an array of target"),
+        // t`error: config value `build.target` is not set`, in which case we
+        // don't wanna log the error
+        None => Ok(None),
     }
-
-    serde_json::from_str(trimmed).context("Failed to parse `build.target` as an array of target")
 }
 
 #[cfg(test)]
@@ -90,7 +92,7 @@ mod tests {
         let sysroot = Sysroot::empty();
         let manifest_path =
             ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
-        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path);
+        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
         assert!(get(cfg, None, &FxHashMap::default()).is_ok());
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/version.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/version.rs
index 91ba8598591..357053d8e82 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/version.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/version.rs
@@ -12,7 +12,7 @@ pub(crate) fn get(
     extra_env: &FxHashMap<String, Option<String>>,
 ) -> Result<Option<Version>, anyhow::Error> {
     let (mut cmd, prefix) = match config {
-        QueryConfig::Cargo(sysroot, cargo_toml) => {
+        QueryConfig::Cargo(sysroot, cargo_toml, _) => {
             (sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env), "cargo ")
         }
         QueryConfig::Rustc(sysroot, current_dir) => {
@@ -44,7 +44,7 @@ mod tests {
         let sysroot = Sysroot::empty();
         let manifest_path =
             ManifestPath::try_from(AbsPathBuf::assert(Utf8PathBuf::from(manifest_path))).unwrap();
-        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path);
+        let cfg = QueryConfig::Cargo(&sysroot, &manifest_path, &None);
         assert!(get(cfg, &FxHashMap::default()).is_ok());
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 43db84b4fa3..677f29e3c60 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -25,11 +25,9 @@ use crate::{
     ProjectJson, ProjectManifest, RustSourceWorkspaceConfig, Sysroot, TargetData, TargetKind,
     WorkspaceBuildScripts,
     build_dependencies::BuildScriptOutput,
-    cargo_workspace::{CargoMetadataConfig, DepKind, PackageData, RustLibSource},
-    env::{
-        cargo_config_build_target_dir, cargo_config_env, inject_cargo_env,
-        inject_cargo_package_env, inject_rustc_tool_env,
-    },
+    cargo_config_file,
+    cargo_workspace::{CargoMetadataConfig, DepKind, FetchMetadata, PackageData, RustLibSource},
+    env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
     project_json::{Crate, CrateArrayIdx},
     sysroot::RustLibSrcWorkspace,
     toolchain_info::{QueryConfig, rustc_cfg, target_data_layout, target_tuple, version},
@@ -270,7 +268,9 @@ impl ProjectWorkspace {
 
         tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot");
         progress("querying project metadata".to_owned());
-        let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml);
+        let config_file = cargo_config_file::read(cargo_toml, extra_env, &sysroot);
+        let config_file_ = config_file.clone();
+        let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml, &config_file_);
         let targets =
             target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default();
         let toolchain = version::get(toolchain_config, extra_env)
@@ -282,10 +282,24 @@ impl ProjectWorkspace {
             .ok()
             .flatten();
 
+        let fetch_metadata = FetchMetadata::new(
+            cargo_toml,
+            workspace_dir,
+            &CargoMetadataConfig {
+                features: features.clone(),
+                targets: targets.clone(),
+                extra_args: extra_args.clone(),
+                extra_env: extra_env.clone(),
+                toolchain_version: toolchain.clone(),
+                kind: "workspace",
+            },
+            &sysroot,
+            *no_deps,
+        );
         let target_dir = config
             .target_dir
             .clone()
-            .or_else(|| cargo_config_build_target_dir(cargo_toml, extra_env, &sysroot))
+            .or_else(|| fetch_metadata.no_deps_metadata().map(|m| m.target_directory.clone()))
             .unwrap_or_else(|| workspace_dir.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
@@ -319,7 +333,7 @@ impl ProjectWorkspace {
                 };
                 rustc_dir.and_then(|rustc_dir| {
                     info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
-                    match CargoWorkspace::fetch_metadata(
+                    match FetchMetadata::new(
                         &rustc_dir,
                         workspace_dir,
                         &CargoMetadataConfig {
@@ -327,15 +341,12 @@ impl ProjectWorkspace {
                             targets: targets.clone(),
                             extra_args: extra_args.clone(),
                             extra_env: extra_env.clone(),
-                            target_dir: target_dir.clone(),
                             toolchain_version: toolchain.clone(),
                             kind: "rustc-dev"
                         },
                         &sysroot,
                         *no_deps,
-                        true,
-                        progress,
-                    ) {
+                    ).exec(&target_dir, true, progress) {
                         Ok((meta, _error)) => {
                             let workspace = CargoWorkspace::new(
                                 meta,
@@ -364,40 +375,22 @@ impl ProjectWorkspace {
                 })
             });
 
-            let cargo_metadata = s.spawn(|| {
-                CargoWorkspace::fetch_metadata(
-                    cargo_toml,
-                    workspace_dir,
-                    &CargoMetadataConfig {
-                        features: features.clone(),
-                        targets: targets.clone(),
-                        extra_args: extra_args.clone(),
-                        extra_env: extra_env.clone(),
-                        target_dir: target_dir.clone(),
-                        toolchain_version: toolchain.clone(),
-                        kind: "workspace",
-                    },
-                    &sysroot,
-                    *no_deps,
-                    false,
-                    progress,
-                )
-            });
+            let cargo_metadata = s.spawn(|| fetch_metadata.exec(&target_dir, false, progress));
             let loaded_sysroot = s.spawn(|| {
                 sysroot.load_workspace(
                     &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
                         config,
                         &targets,
                         toolchain.clone(),
-                        target_dir.clone(),
                     )),
                     config.no_deps,
                     workspace_dir,
+                    &target_dir,
                     progress,
                 )
             });
             let cargo_config_extra_env =
-                s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot));
+                s.spawn(move || cargo_config_env(cargo_toml, &config_file));
             thread::Result::Ok((
                 rustc_cfg.join()?,
                 data_layout.join()?,
@@ -476,9 +469,7 @@ impl ProjectWorkspace {
         let target_dir = config
             .target_dir
             .clone()
-            .or_else(|| {
-                cargo_config_build_target_dir(project_json.manifest()?, &config.extra_env, &sysroot)
-            })
+            .or_else(|| cargo_target_dir(project_json.manifest()?, &config.extra_env, &sysroot))
             .unwrap_or_else(|| project_root.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
@@ -502,6 +493,7 @@ impl ProjectWorkspace {
                         &RustSourceWorkspaceConfig::Json(*sysroot_project),
                         config.no_deps,
                         project_root,
+                        &target_dir,
                         progress,
                     )
                 } else {
@@ -510,10 +502,10 @@ impl ProjectWorkspace {
                             config,
                             &targets,
                             toolchain.clone(),
-                            target_dir,
                         )),
                         config.no_deps,
                         project_root,
+                        &target_dir,
                         progress,
                     )
                 }
@@ -554,7 +546,8 @@ impl ProjectWorkspace {
             None => Sysroot::empty(),
         };
 
-        let query_config = QueryConfig::Cargo(&sysroot, detached_file);
+        let config_file = cargo_config_file::read(detached_file, &config.extra_env, &sysroot);
+        let query_config = QueryConfig::Cargo(&sysroot, detached_file, &config_file);
         let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
         let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
             .unwrap_or_default();
@@ -563,7 +556,7 @@ impl ProjectWorkspace {
         let target_dir = config
             .target_dir
             .clone()
-            .or_else(|| cargo_config_build_target_dir(detached_file, &config.extra_env, &sysroot))
+            .or_else(|| cargo_target_dir(detached_file, &config.extra_env, &sysroot))
             .unwrap_or_else(|| dir.join("target").into());
 
         let loaded_sysroot = sysroot.load_workspace(
@@ -571,17 +564,17 @@ impl ProjectWorkspace {
                 config,
                 &targets,
                 toolchain.clone(),
-                target_dir.clone(),
             )),
             config.no_deps,
             dir,
+            &target_dir,
             &|_| (),
         );
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
 
-        let cargo_script = CargoWorkspace::fetch_metadata(
+        let fetch_metadata = FetchMetadata::new(
             detached_file,
             dir,
             &CargoMetadataConfig {
@@ -589,25 +582,26 @@ impl ProjectWorkspace {
                 targets,
                 extra_args: config.extra_args.clone(),
                 extra_env: config.extra_env.clone(),
-                target_dir,
                 toolchain_version: toolchain.clone(),
                 kind: "detached-file",
             },
             &sysroot,
             config.no_deps,
-            false,
-            &|_| (),
-        )
-        .ok()
-        .map(|(ws, error)| {
-            let cargo_config_extra_env =
-                cargo_config_env(detached_file, &config.extra_env, &sysroot);
-            (
-                CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
-                WorkspaceBuildScripts::default(),
-                error.map(Arc::new),
-            )
-        });
+        );
+        let target_dir = config
+            .target_dir
+            .clone()
+            .or_else(|| fetch_metadata.no_deps_metadata().map(|m| m.target_directory.clone()))
+            .unwrap_or_else(|| dir.join("target").into());
+        let cargo_script =
+            fetch_metadata.exec(&target_dir, false, &|_| ()).ok().map(|(ws, error)| {
+                let cargo_config_extra_env = cargo_config_env(detached_file, &config_file);
+                (
+                    CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
+                    WorkspaceBuildScripts::default(),
+                    error.map(Arc::new),
+                )
+            });
 
         Ok(ProjectWorkspace {
             kind: ProjectWorkspaceKind::DetachedFile {
@@ -1889,15 +1883,33 @@ fn sysroot_metadata_config(
     config: &CargoConfig,
     targets: &[String],
     toolchain_version: Option<Version>,
-    target_dir: Utf8PathBuf,
 ) -> CargoMetadataConfig {
     CargoMetadataConfig {
         features: Default::default(),
         targets: targets.to_vec(),
         extra_args: Default::default(),
         extra_env: config.extra_env.clone(),
-        target_dir,
         toolchain_version,
         kind: "sysroot",
     }
 }
+
+fn cargo_target_dir(
+    manifest: &ManifestPath,
+    extra_env: &FxHashMap<String, Option<String>>,
+    sysroot: &Sysroot,
+) -> Option<Utf8PathBuf> {
+    let cargo = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
+    let mut meta = cargo_metadata::MetadataCommand::new();
+    meta.cargo_path(cargo.get_program());
+    meta.manifest_path(manifest);
+    // `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve.
+    // So we can use it to get `target_directory` before copying lockfiles
+    let mut other_options = vec!["--no-deps".to_owned()];
+    if manifest.is_rust_manifest() {
+        meta.env("RUSTC_BOOTSTRAP", "1");
+        other_options.push("-Zscript".to_owned());
+    }
+    meta.other_options(other_options);
+    meta.exec().map(|m| m.target_directory).ok()
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 0ee01982fea..fc89f486f84 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -796,7 +796,7 @@ impl flags::AnalysisStats {
             // region:expressions
             let (previous_exprs, previous_unknown, previous_partially_unknown) =
                 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
-            for (expr_id, _) in body.exprs.iter() {
+            for (expr_id, _) in body.exprs() {
                 let ty = &inference_result[expr_id];
                 num_exprs += 1;
                 let unknown_or_partial = if ty.is_unknown() {
@@ -901,7 +901,7 @@ impl flags::AnalysisStats {
             // region:patterns
             let (previous_pats, previous_unknown, previous_partially_unknown) =
                 (num_pats, num_pats_unknown, num_pats_partially_unknown);
-            for (pat_id, _) in body.pats.iter() {
+            for (pat_id, _) in body.pats() {
                 let ty = &inference_result[pat_id];
                 num_pats += 1;
                 let unknown_or_partial = if ty.is_unknown() {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index f97bf832442..30ac93fb6f8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -9,6 +9,7 @@ use hir::{ChangeWithProcMacros, Crate};
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use ide_db::base_db;
 use itertools::Either;
+use paths::Utf8PathBuf;
 use profile::StopWatch;
 use project_model::toolchain_info::{QueryConfig, target_data_layout};
 use project_model::{
@@ -79,6 +80,7 @@ impl Tester {
             &RustSourceWorkspaceConfig::default_cargo(),
             false,
             &path,
+            &Utf8PathBuf::default(),
             &|_| (),
         );
         if let Some(loaded_sysroot) = loaded_sysroot {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 8a848fb848c..292be1d5315 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -911,7 +911,8 @@ pub(crate) fn folding_range(
         | FoldKind::Array
         | FoldKind::TraitAliases
         | FoldKind::ExternCrates
-        | FoldKind::MatchArm => None,
+        | FoldKind::MatchArm
+        | FoldKind::Function => None,
     };
 
     let range = range(line_index, fold.range);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 59073af983b..1b940c70da6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -880,7 +880,8 @@ fn main() {{}}
 
 #[test]
 fn diagnostics_dont_block_typing() {
-    if skip_slow_tests() {
+    if skip_slow_tests() || std::env::var("CI").is_ok() {
+        // FIXME: This test is failing too frequently (therefore we disable it on CI).
         return;
     }
 
diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
index 121d2e33243..a9288ecd6fa 100644
--- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs
+++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
@@ -92,6 +92,7 @@ impl fmt::Debug for ErasedFileAstId {
             Use,
             Impl,
             BlockExpr,
+            AsmExpr,
             Fixup,
         );
         if f.alternate() {
@@ -144,6 +145,10 @@ enum ErasedFileAstIdKind {
     Impl,
     /// Associated with [`BlockExprFileAstId`].
     BlockExpr,
+    // `global_asm!()` is an item, so we need to give it an `AstId`. So we give to all inline asm
+    // because incrementality is not a problem, they will always be the only item in the macro file,
+    // and memory usage also not because they're rare.
+    AsmExpr,
     /// Keep this last.
     Root,
 }
@@ -204,14 +209,17 @@ impl ErasedFileAstId {
             .or_else(|| extern_block_ast_id(node, index_map))
             .or_else(|| use_ast_id(node, index_map))
             .or_else(|| impl_ast_id(node, index_map))
+            .or_else(|| asm_expr_ast_id(node, index_map))
     }
 
     fn should_alloc(node: &SyntaxNode) -> bool {
-        should_alloc_has_name(node)
-            || should_alloc_assoc_item(node)
-            || ast::ExternBlock::can_cast(node.kind())
-            || ast::Use::can_cast(node.kind())
-            || ast::Impl::can_cast(node.kind())
+        let kind = node.kind();
+        should_alloc_has_name(kind)
+            || should_alloc_assoc_item(kind)
+            || ast::ExternBlock::can_cast(kind)
+            || ast::Use::can_cast(kind)
+            || ast::Impl::can_cast(kind)
+            || ast::AsmExpr::can_cast(kind)
     }
 
     #[inline]
@@ -278,7 +286,6 @@ impl<N> FileAstId<N> {
 
 #[derive(Hash)]
 struct ErasedHasNameFileAstId<'a> {
-    kind: SyntaxKind,
     name: &'a str,
 }
 
@@ -332,6 +339,19 @@ fn use_ast_id(
     }
 }
 
+impl AstIdNode for ast::AsmExpr {}
+
+fn asm_expr_ast_id(
+    node: &SyntaxNode,
+    index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+    if ast::AsmExpr::can_cast(node.kind()) {
+        Some(index_map.new_id(ErasedFileAstIdKind::AsmExpr, ()))
+    } else {
+        None
+    }
+}
+
 impl AstIdNode for ast::Impl {}
 
 fn impl_ast_id(
@@ -433,7 +453,6 @@ macro_rules! register_has_name_ast_id {
         )+
 
         fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) -> Option<ErasedFileAstId> {
-            let kind = node.kind();
             match_ast! {
                 match node {
                     $(
@@ -441,7 +460,6 @@ macro_rules! register_has_name_ast_id {
                             let name = node.$name_method();
                             let name = name.as_ref().map_or("", |it| it.text_non_mutable());
                             let result = ErasedHasNameFileAstId {
-                                kind,
                                 name,
                             };
                             Some(index_map.new_id(ErasedFileAstIdKind::$ident, result))
@@ -452,8 +470,7 @@ macro_rules! register_has_name_ast_id {
             }
         }
 
-        fn should_alloc_has_name(node: &SyntaxNode) -> bool {
-            let kind = node.kind();
+        fn should_alloc_has_name(kind: SyntaxKind) -> bool {
             false $( || ast::$ident::can_cast(kind) )*
         }
     };
@@ -483,7 +500,6 @@ macro_rules! register_assoc_item_ast_id {
             index_map: &mut ErasedAstIdNextIndexMap,
             parent: Option<&ErasedFileAstId>,
         ) -> Option<ErasedFileAstId> {
-            let kind = node.kind();
             match_ast! {
                 match node {
                     $(
@@ -491,7 +507,6 @@ macro_rules! register_assoc_item_ast_id {
                             let name = $name_callback(node);
                             let name = name.as_ref().map_or("", |it| it.text_non_mutable());
                             let properties = ErasedHasNameFileAstId {
-                                kind,
                                 name,
                             };
                             let result = ErasedAssocItemFileAstId {
@@ -506,8 +521,7 @@ macro_rules! register_assoc_item_ast_id {
             }
         }
 
-        fn should_alloc_assoc_item(node: &SyntaxNode) -> bool {
-            let kind = node.kind();
+        fn should_alloc_assoc_item(kind: SyntaxKind) -> bool {
             false $( || ast::$ident::can_cast(kind) )*
         }
     };
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 3f439472337..4cbc88cfb5e 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -158,6 +158,7 @@ Item =
 | TypeAlias
 | Union
 | Use
+| AsmExpr
 
 MacroRules =
   Attr* Visibility?
@@ -409,7 +410,8 @@ OffsetOfExpr =
 // global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")"
 // format_string := STRING_LITERAL / RAW_STRING_LITERAL
 AsmExpr =
-  Attr* 'builtin' '#' 'asm' '(' template:(Expr (',' Expr)*) (AsmPiece (',' AsmPiece)*)? ','? ')'
+  Attr* 'builtin' '#' ( 'asm' | 'global_asm' | 'naked_asm' )
+  '(' template:(Expr (',' Expr)*) (AsmPiece (',' AsmPiece)*)? ','? ')'
 
 // operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
 AsmOperandExpr = in_expr:Expr ('=>' out_expr:Expr)?
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index e60243f2c91..e902516471d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -406,42 +406,6 @@ impl ast::WhereClause {
     }
 }
 
-impl ast::TypeParam {
-    pub fn remove_default(&self) {
-        if let Some((eq, last)) = self
-            .syntax()
-            .children_with_tokens()
-            .find(|it| it.kind() == T![=])
-            .zip(self.syntax().last_child_or_token())
-        {
-            ted::remove_all(eq..=last);
-
-            // remove any trailing ws
-            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
-                last.detach();
-            }
-        }
-    }
-}
-
-impl ast::ConstParam {
-    pub fn remove_default(&self) {
-        if let Some((eq, last)) = self
-            .syntax()
-            .children_with_tokens()
-            .find(|it| it.kind() == T![=])
-            .zip(self.syntax().last_child_or_token())
-        {
-            ted::remove_all(eq..=last);
-
-            // remove any trailing ws
-            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
-                last.detach();
-            }
-        }
-    }
-}
-
 pub trait Removable: AstNode {
     fn remove(&self);
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 79a9f4da338..2b862465420 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -118,6 +118,14 @@ impl AsmExpr {
     pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
     #[inline]
     pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    #[inline]
+    pub fn global_asm_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![global_asm])
+    }
+    #[inline]
+    pub fn naked_asm_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![naked_asm])
+    }
 }
 pub struct AsmLabel {
     pub(crate) syntax: SyntaxNode,
@@ -2087,6 +2095,7 @@ impl ast::HasAttrs for GenericParam {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Item {
+    AsmExpr(AsmExpr),
     Const(Const),
     Enum(Enum),
     ExternBlock(ExternBlock),
@@ -2106,7 +2115,6 @@ pub enum Item {
     Use(Use),
 }
 impl ast::HasAttrs for Item {}
-impl ast::HasDocComments for Item {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Pat {
@@ -8409,6 +8417,10 @@ impl AstNode for GenericParam {
         }
     }
 }
+impl From<AsmExpr> for Item {
+    #[inline]
+    fn from(node: AsmExpr) -> Item { Item::AsmExpr(node) }
+}
 impl From<Const> for Item {
     #[inline]
     fn from(node: Const) -> Item { Item::Const(node) }
@@ -8482,7 +8494,8 @@ impl AstNode for Item {
     fn can_cast(kind: SyntaxKind) -> bool {
         matches!(
             kind,
-            CONST
+            ASM_EXPR
+                | CONST
                 | ENUM
                 | EXTERN_BLOCK
                 | EXTERN_CRATE
@@ -8504,6 +8517,7 @@ impl AstNode for Item {
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
+            ASM_EXPR => Item::AsmExpr(AsmExpr { syntax }),
             CONST => Item::Const(Const { syntax }),
             ENUM => Item::Enum(Enum { syntax }),
             EXTERN_BLOCK => Item::ExternBlock(ExternBlock { syntax }),
@@ -8528,6 +8542,7 @@ impl AstNode for Item {
     #[inline]
     fn syntax(&self) -> &SyntaxNode {
         match self {
+            Item::AsmExpr(it) => &it.syntax,
             Item::Const(it) => &it.syntax,
             Item::Enum(it) => &it.syntax,
             Item::ExternBlock(it) => &it.syntax,
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 309332873cb..d67f24fda96 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -680,7 +680,7 @@ pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::TupleEx
     let expr = elements.into_iter().format(", ");
     expr_from_text(&format!("({expr})"))
 }
-pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
+pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::BinExpr {
     expr_from_text(&format!("{lhs} = {rhs}"))
 }
 fn expr_from_text<E: Into<ast::Expr> + AstNode>(text: &str) -> E {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 17cc5f9c057..1ba61073151 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -440,6 +440,19 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_assignment(&self, lhs: ast::Expr, rhs: ast::Expr) -> ast::BinExpr {
+        let ast = make::expr_assignment(lhs.clone(), rhs.clone()).clone_for_update();
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(lhs.syntax().clone(), ast.lhs().unwrap().syntax().clone());
+            builder.map_node(rhs.syntax().clone(), ast.rhs().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
         let ast::Expr::BinExpr(ast) =
             make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update()
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index dc1eba1a1ab..7b719b5dec7 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -1011,8 +1011,7 @@ pub mod ops {
     }
 
     #[lang = "add_assign"]
-    #[const_trait]
-    pub trait AddAssign<Rhs = Self> {
+    pub const trait AddAssign<Rhs = Self> {
         fn add_assign(&mut self, rhs: Rhs);
     }
 
@@ -1941,6 +1940,7 @@ pub mod prelude {
             clone::Clone,                            // :clone
             cmp::{Eq, PartialEq},                    // :eq
             cmp::{Ord, PartialOrd},                  // :ord
+            convert::AsMut,                          // :as_mut
             convert::AsRef,                          // :as_ref
             convert::{From, Into, TryFrom, TryInto}, // :from
             default::Default,                        // :default
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index 35a5a4d82b2..1fc1da50a0a 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -16,6 +16,9 @@ crossbeam-channel.workspace = true
 [dev-dependencies]
 lsp-types = "=0.95"
 ctrlc = "3.4.7"
+anyhow.workspace     = true
+rustc-hash.workspace = true
+toolchain.workspace  = true
 
 [lints]
 workspace = true
diff --git a/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs b/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs
deleted file mode 100644
index 6b3acda7bcd..00000000000
--- a/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs
+++ /dev/null
@@ -1,132 +0,0 @@
-//! A minimal example LSP server that can only respond to the `gotoDefinition` request. To use
-//! this example, execute it and then send an `initialize` request.
-//!
-//! ```no_run
-//! Content-Length: 85
-//!
-//! {"jsonrpc": "2.0", "method": "initialize", "id": 1, "params": {"capabilities": {}}}
-//! ```
-//!
-//! This will respond with a server response. Then send it a `initialized` notification which will
-//! have no response.
-//!
-//! ```no_run
-//! Content-Length: 59
-//!
-//! {"jsonrpc": "2.0", "method": "initialized", "params": {}}
-//! ```
-//!
-//! Once these two are sent, then we enter the main loop of the server. The only request this
-//! example can handle is `gotoDefinition`:
-//!
-//! ```no_run
-//! Content-Length: 159
-//!
-//! {"jsonrpc": "2.0", "method": "textDocument/definition", "id": 2, "params": {"textDocument": {"uri": "file://temp"}, "position": {"line": 1, "character": 1}}}
-//! ```
-//!
-//! To finish up without errors, send a shutdown request:
-//!
-//! ```no_run
-//! Content-Length: 67
-//!
-//! {"jsonrpc": "2.0", "method": "shutdown", "id": 3, "params": null}
-//! ```
-//!
-//! The server will exit the main loop and finally we send a `shutdown` notification to stop
-//! the server.
-//!
-//! ```
-//! Content-Length: 54
-//!
-//! {"jsonrpc": "2.0", "method": "exit", "params": null}
-//! ```
-
-#![allow(clippy::print_stderr)]
-
-use std::error::Error;
-
-use lsp_types::OneOf;
-use lsp_types::{
-    GotoDefinitionResponse, InitializeParams, ServerCapabilities, request::GotoDefinition,
-};
-
-use lsp_server::{Connection, ExtractError, Message, Request, RequestId, Response};
-
-fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
-    // Note that  we must have our logging only write out to stderr.
-    eprintln!("starting generic LSP server");
-
-    // Create the transport. Includes the stdio (stdin and stdout) versions but this could
-    // also be implemented to use sockets or HTTP.
-    let (connection, io_threads) = Connection::stdio();
-
-    // Run the server and wait for the two threads to end (typically by trigger LSP Exit event).
-    let server_capabilities = serde_json::to_value(&ServerCapabilities {
-        definition_provider: Some(OneOf::Left(true)),
-        ..Default::default()
-    })
-    .unwrap();
-    let initialization_params = match connection.initialize(server_capabilities) {
-        Ok(it) => it,
-        Err(e) => {
-            if e.channel_is_disconnected() {
-                io_threads.join()?;
-            }
-            return Err(e.into());
-        }
-    };
-    main_loop(connection, initialization_params)?;
-    io_threads.join()?;
-
-    // Shut down gracefully.
-    eprintln!("shutting down server");
-    Ok(())
-}
-
-fn main_loop(
-    connection: Connection,
-    params: serde_json::Value,
-) -> Result<(), Box<dyn Error + Sync + Send>> {
-    let _params: InitializeParams = serde_json::from_value(params).unwrap();
-    eprintln!("starting example main loop");
-    for msg in &connection.receiver {
-        eprintln!("got msg: {msg:?}");
-        match msg {
-            Message::Request(req) => {
-                if connection.handle_shutdown(&req)? {
-                    return Ok(());
-                }
-                eprintln!("got request: {req:?}");
-                match cast::<GotoDefinition>(req) {
-                    Ok((id, params)) => {
-                        eprintln!("got gotoDefinition request #{id}: {params:?}");
-                        let result = Some(GotoDefinitionResponse::Array(Vec::new()));
-                        let result = serde_json::to_value(&result).unwrap();
-                        let resp = Response { id, result: Some(result), error: None };
-                        connection.sender.send(Message::Response(resp))?;
-                        continue;
-                    }
-                    Err(err @ ExtractError::JsonError { .. }) => panic!("{err:?}"),
-                    Err(ExtractError::MethodMismatch(req)) => req,
-                };
-                // ...
-            }
-            Message::Response(resp) => {
-                eprintln!("got response: {resp:?}");
-            }
-            Message::Notification(not) => {
-                eprintln!("got notification: {not:?}");
-            }
-        }
-    }
-    Ok(())
-}
-
-fn cast<R>(req: Request) -> Result<(RequestId, R::Params), ExtractError<Request>>
-where
-    R: lsp_types::request::Request,
-    R::Params: serde::de::DeserializeOwned,
-{
-    req.extract(R::METHOD)
-}
diff --git a/src/tools/rust-analyzer/lib/lsp-server/examples/manual_test.sh b/src/tools/rust-analyzer/lib/lsp-server/examples/manual_test.sh
new file mode 100755
index 00000000000..d028ac43301
--- /dev/null
+++ b/src/tools/rust-analyzer/lib/lsp-server/examples/manual_test.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+# Simple nine-packet LSP test for examples/minimal_lsp.rs
+# Usage (two tabs):
+#
+#   mkfifo /tmp/lsp_pipe          # one-time setup
+#   # tab 1 – run the server
+#   cat /tmp/lsp_pipe | cargo run --example minimal_lsp
+#
+#   # tab 2 – fire the packets (this script)
+#   bash examples/manual_test.sh          # blocks until server exits
+#
+# If you don’t use a second tab, run the script in the background:
+#
+#   bash examples/manual_test.sh &        # writer in background
+#   cat /tmp/lsp_pipe | cargo run --example minimal_lsp
+#
+# The script opens /tmp/lsp_pipe for writing (exec 3>) and sends each JSON
+# packet with a correct Content-Length header.
+#
+# One-liner alternative (single terminal, no FIFO):
+#
+#   cargo run --example minimal_lsp <<'EOF'
+#     … nine packets …
+#   EOF
+#
+# Both approaches feed identical bytes to minimal_lsp via stdin.
+
+set -eu
+PIPE=${1:-/tmp/lsp_pipe}
+
+mkfifo -m 600 "$PIPE" 2>/dev/null || true       # create once, ignore if exists
+
+# open write end so the fifo stays open
+exec 3> "$PIPE"
+
+send() {
+  local body=$1
+  local len=$(printf '%s' "$body" | wc -c)
+  printf 'Content-Length: %d\r\n\r\n%s' "$len" "$body" >&3
+}
+
+send '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}'
+send '{"jsonrpc":"2.0","method":"initialized","params":{}}'
+send '{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///tmp/foo.rs","languageId":"rust","version":1,"text":"fn  main( ){println!(\"hi\") }"}}}'
+send '{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"position":{"line":0,"character":0}}}'
+send '{"jsonrpc":"2.0","id":3,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"position":{"line":0,"character":0}}}'
+send '{"jsonrpc":"2.0","id":4,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"position":{"line":0,"character":0}}}'
+send '{"jsonrpc":"2.0","id":5,"method":"textDocument/formatting","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"options":{"tabSize":4,"insertSpaces":true}}}'
+send '{"jsonrpc":"2.0","id":6,"method":"shutdown","params":null}'
+send '{"jsonrpc":"2.0","method":"exit","params":null}'
+
+exec 3>&-
+echo "Packets sent – watch the other terminal for responses."
diff --git a/src/tools/rust-analyzer/lib/lsp-server/examples/minimal_lsp.rs b/src/tools/rust-analyzer/lib/lsp-server/examples/minimal_lsp.rs
new file mode 100644
index 00000000000..5eef999e062
--- /dev/null
+++ b/src/tools/rust-analyzer/lib/lsp-server/examples/minimal_lsp.rs
@@ -0,0 +1,335 @@
+//! Minimal Language‑Server‑Protocol example: **`minimal_lsp.rs`**
+//! =============================================================
+//!
+//! | ↔ / ← | LSP method | What the implementation does |
+//! |-------|------------|------------------------------|
+//! | ↔ | `initialize` / `initialized` | capability handshake |
+//! | ← | `textDocument/publishDiagnostics` | pushes a dummy info diagnostic whenever the buffer changes |
+//! | ← | `textDocument/definition` | echoes an empty location array so the jump works |
+//! | ← | `textDocument/completion` | offers one hard‑coded item `HelloFromLSP` |
+//! | ← | `textDocument/hover` | shows *Hello from minimal_lsp* markdown |
+//! | ← | `textDocument/formatting` | pipes the doc through **rustfmt** and returns a full‑file edit |
+//!
+//! ### Quick start
+//! ```bash
+//! cd rust-analyzer/lib/lsp-server
+//! cargo run --example minimal_lsp
+//! ```
+//!
+//! ### Minimal manual session (all nine packets)
+//! ```no_run
+//! # 1. initialize - server replies with capabilities
+//! Content-Length: 85
+
+//! {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}
+//!
+//! # 2. initialized - no response expected
+//! Content-Length: 59
+
+//! {"jsonrpc":"2.0","method":"initialized","params":{}}
+//!
+//! # 3. didOpen - provide initial buffer text
+//! Content-Length: 173
+
+//! {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///tmp/foo.rs","languageId":"rust","version":1,"text":"fn  main( ){println!(\"hi\") }"}}}
+//!
+//! # 4. completion - expect HelloFromLSP
+//! Content-Length: 139
+
+//! {"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"position":{"line":0,"character":0}}}
+//!
+//! # 5. hover - expect markdown greeting
+//! Content-Length: 135
+
+//! {"jsonrpc":"2.0","id":3,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"position":{"line":0,"character":0}}}
+//!
+//! # 6. goto-definition - dummy empty array
+//! Content-Length: 139
+
+//! {"jsonrpc":"2.0","id":4,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"position":{"line":0,"character":0}}}
+//!
+//! # 7. formatting - rustfmt full document
+//! Content-Length: 157
+
+//! {"jsonrpc":"2.0","id":5,"method":"textDocument/formatting","params":{"textDocument":{"uri":"file:///tmp/foo.rs"},"options":{"tabSize":4,"insertSpaces":true}}}
+//!
+//! # 8. shutdown request - server acks and prepares to exit
+//! Content-Length: 67
+
+//! {"jsonrpc":"2.0","id":6,"method":"shutdown","params":null}
+//!
+//! # 9. exit notification - terminates the server
+//! Content-Length: 54
+
+//! {"jsonrpc":"2.0","method":"exit","params":null}
+//! ```
+//!
+
+use std::{error::Error, io::Write};
+
+use rustc_hash::FxHashMap; // fast hash map
+use std::process::Stdio;
+use toolchain::command; // clippy-approved wrapper
+
+#[allow(clippy::print_stderr, clippy::disallowed_types, clippy::disallowed_methods)]
+use anyhow::{Context, Result, anyhow, bail};
+use lsp_server::{Connection, Message, Request as ServerRequest, RequestId, Response};
+use lsp_types::notification::Notification as _; // for METHOD consts
+use lsp_types::request::Request as _;
+use lsp_types::{
+    CompletionItem,
+    CompletionItemKind,
+    // capability helpers
+    CompletionOptions,
+    CompletionResponse,
+    Diagnostic,
+    DiagnosticSeverity,
+    DidChangeTextDocumentParams,
+    DidOpenTextDocumentParams,
+    DocumentFormattingParams,
+    Hover,
+    HoverContents,
+    HoverProviderCapability,
+    // core
+    InitializeParams,
+    MarkedString,
+    OneOf,
+    Position,
+    PublishDiagnosticsParams,
+    Range,
+    ServerCapabilities,
+    TextDocumentSyncCapability,
+    TextDocumentSyncKind,
+    TextEdit,
+    Url,
+    // notifications
+    notification::{DidChangeTextDocument, DidOpenTextDocument, PublishDiagnostics},
+    // requests
+    request::{Completion, Formatting, GotoDefinition, HoverRequest},
+}; // for METHOD consts
+
+// =====================================================================
+// main
+// =====================================================================
+
+#[allow(clippy::print_stderr)]
+fn main() -> std::result::Result<(), Box<dyn Error + Sync + Send>> {
+    log::error!("starting minimal_lsp");
+
+    // transport
+    let (connection, io_thread) = Connection::stdio();
+
+    // advertised capabilities
+    let caps = ServerCapabilities {
+        text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL)),
+        completion_provider: Some(CompletionOptions::default()),
+        definition_provider: Some(OneOf::Left(true)),
+        hover_provider: Some(HoverProviderCapability::Simple(true)),
+        document_formatting_provider: Some(OneOf::Left(true)),
+        ..Default::default()
+    };
+    let init_value = serde_json::json!({
+        "capabilities": caps,
+        "offsetEncoding": ["utf-8"],
+    });
+
+    let init_params = connection.initialize(init_value)?;
+    main_loop(connection, init_params)?;
+    io_thread.join()?;
+    log::error!("shutting down server");
+    Ok(())
+}
+
+// =====================================================================
+// event loop
+// =====================================================================
+
+fn main_loop(
+    connection: Connection,
+    params: serde_json::Value,
+) -> std::result::Result<(), Box<dyn Error + Sync + Send>> {
+    let _init: InitializeParams = serde_json::from_value(params)?;
+    let mut docs: FxHashMap<Url, String> = FxHashMap::default();
+
+    for msg in &connection.receiver {
+        match msg {
+            Message::Request(req) => {
+                if connection.handle_shutdown(&req)? {
+                    break;
+                }
+                if let Err(err) = handle_request(&connection, &req, &mut docs) {
+                    log::error!("[lsp] request {} failed: {err}", &req.method);
+                }
+            }
+            Message::Notification(note) => {
+                if let Err(err) = handle_notification(&connection, &note, &mut docs) {
+                    log::error!("[lsp] notification {} failed: {err}", note.method);
+                }
+            }
+            Message::Response(resp) => log::error!("[lsp] response: {resp:?}"),
+        }
+    }
+    Ok(())
+}
+
+// =====================================================================
+// notifications
+// =====================================================================
+
+fn handle_notification(
+    conn: &Connection,
+    note: &lsp_server::Notification,
+    docs: &mut FxHashMap<Url, String>,
+) -> Result<()> {
+    match note.method.as_str() {
+        DidOpenTextDocument::METHOD => {
+            let p: DidOpenTextDocumentParams = serde_json::from_value(note.params.clone())?;
+            let uri = p.text_document.uri;
+            docs.insert(uri.clone(), p.text_document.text);
+            publish_dummy_diag(conn, &uri)?;
+        }
+        DidChangeTextDocument::METHOD => {
+            let p: DidChangeTextDocumentParams = serde_json::from_value(note.params.clone())?;
+            if let Some(change) = p.content_changes.into_iter().next() {
+                let uri = p.text_document.uri;
+                docs.insert(uri.clone(), change.text);
+                publish_dummy_diag(conn, &uri)?;
+            }
+        }
+        _ => {}
+    }
+    Ok(())
+}
+
+// =====================================================================
+// requests
+// =====================================================================
+
+fn handle_request(
+    conn: &Connection,
+    req: &ServerRequest,
+    docs: &mut FxHashMap<Url, String>,
+) -> Result<()> {
+    match req.method.as_str() {
+        GotoDefinition::METHOD => {
+            send_ok(conn, req.id.clone(), &lsp_types::GotoDefinitionResponse::Array(Vec::new()))?;
+        }
+        Completion::METHOD => {
+            let item = CompletionItem {
+                label: "HelloFromLSP".into(),
+                kind: Some(CompletionItemKind::FUNCTION),
+                detail: Some("dummy completion".into()),
+                ..Default::default()
+            };
+            send_ok(conn, req.id.clone(), &CompletionResponse::Array(vec![item]))?;
+        }
+        HoverRequest::METHOD => {
+            let hover = Hover {
+                contents: HoverContents::Scalar(MarkedString::String(
+                    "Hello from *minimal_lsp*".into(),
+                )),
+                range: None,
+            };
+            send_ok(conn, req.id.clone(), &hover)?;
+        }
+        Formatting::METHOD => {
+            let p: DocumentFormattingParams = serde_json::from_value(req.params.clone())?;
+            let uri = p.text_document.uri;
+            let text = docs
+                .get(&uri)
+                .ok_or_else(|| anyhow!("document not in cache – did you send DidOpen?"))?;
+            let formatted = run_rustfmt(text)?;
+            let edit = TextEdit { range: full_range(text), new_text: formatted };
+            send_ok(conn, req.id.clone(), &vec![edit])?;
+        }
+        _ => send_err(
+            conn,
+            req.id.clone(),
+            lsp_server::ErrorCode::MethodNotFound,
+            "unhandled method",
+        )?,
+    }
+    Ok(())
+}
+
+// =====================================================================
+// diagnostics
+// =====================================================================
+fn publish_dummy_diag(conn: &Connection, uri: &Url) -> Result<()> {
+    let diag = Diagnostic {
+        range: Range::new(Position::new(0, 0), Position::new(0, 1)),
+        severity: Some(DiagnosticSeverity::INFORMATION),
+        code: None,
+        code_description: None,
+        source: Some("minimal_lsp".into()),
+        message: "dummy diagnostic".into(),
+        related_information: None,
+        tags: None,
+        data: None,
+    };
+    let params =
+        PublishDiagnosticsParams { uri: uri.clone(), diagnostics: vec![diag], version: None };
+    conn.sender.send(Message::Notification(lsp_server::Notification::new(
+        PublishDiagnostics::METHOD.to_owned(),
+        params,
+    )))?;
+    Ok(())
+}
+
+// =====================================================================
+// helpers
+// =====================================================================
+
+fn run_rustfmt(input: &str) -> Result<String> {
+    let cwd = std::env::current_dir().expect("can't determine CWD");
+    let mut child = command("rustfmt", &cwd, &FxHashMap::default())
+        .arg("--emit")
+        .arg("stdout")
+        .stdin(Stdio::piped())
+        .stdout(Stdio::piped())
+        .stderr(Stdio::piped())
+        .spawn()
+        .context("failed to spawn rustfmt – is it installed?")?;
+
+    let Some(stdin) = child.stdin.as_mut() else {
+        bail!("stdin unavailable");
+    };
+    stdin.write_all(input.as_bytes())?;
+    let output = child.wait_with_output()?;
+    if !output.status.success() {
+        let stderr = String::from_utf8_lossy(&output.stderr);
+        bail!("rustfmt failed: {stderr}");
+    }
+    Ok(String::from_utf8(output.stdout)?)
+}
+
+fn full_range(text: &str) -> Range {
+    let last_line_idx = text.lines().count().saturating_sub(1) as u32;
+    let last_col = text.lines().last().map_or(0, |l| l.chars().count()) as u32;
+    Range::new(Position::new(0, 0), Position::new(last_line_idx, last_col))
+}
+
+fn send_ok<T: serde::Serialize>(conn: &Connection, id: RequestId, result: &T) -> Result<()> {
+    let resp = Response { id, result: Some(serde_json::to_value(result)?), error: None };
+    conn.sender.send(Message::Response(resp))?;
+    Ok(())
+}
+
+fn send_err(
+    conn: &Connection,
+    id: RequestId,
+    code: lsp_server::ErrorCode,
+    msg: &str,
+) -> Result<()> {
+    let resp = Response {
+        id,
+        result: None,
+        error: Some(lsp_server::ResponseError {
+            code: code as i32,
+            message: msg.into(),
+            data: None,
+        }),
+    };
+    conn.sender.send(Message::Response(resp))?;
+    Ok(())
+}
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 902793225ea..57ff326ce5a 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-ad3b7257615c28aaf8212a189ec032b8af75de51
+a9fb6103b05c6ad6eee6bed4c0bb5a2e8e1024c6
diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs
index d8cbf894520..b9f570fe0e3 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs
@@ -116,6 +116,8 @@ const CONTEXTUAL_KEYWORDS: &[&str] =
 // keywords we use for special macro expansions
 const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &[
     "asm",
+    "naked_asm",
+    "global_asm",
     "att_syntax",
     "builtin",
     "clobber_abi",
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 27798d6aeb0..e363668d462 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -19,9 +19,9 @@ dependencies = [
 
 [[package]]
 name = "ammonia"
-version = "4.1.0"
+version = "4.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ada2ee439075a3e70b6992fce18ac4e407cd05aea9ca3f75d2c0b0c20bbb364"
+checksum = "d6b346764dd0814805de8abf899fe03065bcee69bb1a4771c785817e39f3978f"
 dependencies = [
  "cssparser",
  "html5ever",
@@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
 
 [[package]]
 name = "cc"
-version = "1.2.29"
+version = "1.2.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
+checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
 dependencies = [
  "shlex",
 ]
@@ -185,9 +185,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
+checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
+checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
 dependencies = [
  "anstream",
  "anstyle",
@@ -208,18 +208,18 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.54"
+version = "4.5.55"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677"
+checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
+checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -256,9 +256,9 @@ dependencies = [
 
 [[package]]
 name = "crc32fast"
-version = "1.4.2"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
 dependencies = [
  "cfg-if",
 ]
@@ -582,12 +582,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
 [[package]]
 name = "html5ever"
-version = "0.31.0"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c"
+checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4"
 dependencies = [
  "log",
- "mac",
  "markup5ever",
  "match_token",
 ]
@@ -863,9 +862,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "markup5ever"
-version = "0.16.2"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e4cd8c02f18a011991a039855480c64d74291c5792fcc160d55d77dc4de4a39"
+checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3"
 dependencies = [
  "log",
  "tendril",
@@ -874,9 +873,9 @@ dependencies = [
 
 [[package]]
 name = "match_token"
-version = "0.1.0"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
+checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1394,15 +1393,15 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "1.0.7"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
 dependencies = [
  "bitflags 2.9.1",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -1460,9 +1459,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.140"
+version = "1.0.141"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
 dependencies = [
  "itoa",
  "memchr",
@@ -2103,9 +2102,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
 
 [[package]]
 name = "winnow"
-version = "0.7.11"
+version = "0.7.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
+checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
 dependencies = [
  "memchr",
 ]
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index 0e35861fbf7..5b86bea8932 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -1,63 +1,15 @@
+use std::env;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::sync::Arc;
-use std::{env, fs};
 
+use build_helper::npm;
 use build_helper::util::try_run;
 use compiletest::directives::TestProps;
 use config::Config;
 
 mod config;
 
-fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
-    let mut command = Command::new(&npm);
-    command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
-    if global {
-        command.arg("--global");
-    }
-    let lines = match command.output() {
-        Ok(output) => String::from_utf8_lossy(&output.stdout).into_owned(),
-        Err(e) => {
-            eprintln!(
-                "path to npm can be wrong, provided path: {npm:?}. Try to set npm path \
-            in bootstrap.toml in [build.npm]",
-            );
-            panic!("{:?}", e)
-        }
-    };
-    lines
-        .lines()
-        .find_map(|l| l.rsplit(':').next()?.strip_prefix("browser-ui-test@"))
-        .map(|v| v.to_owned())
-}
-
-fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
-    get_browser_ui_test_version_inner(npm, false)
-        .or_else(|| get_browser_ui_test_version_inner(npm, true))
-}
-
-fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
-    match fs::read_to_string(
-        src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"),
-    ) {
-        Ok(v) => {
-            if v.trim() != installed_version {
-                eprintln!(
-                    "⚠️ Installed version of browser-ui-test (`{}`) is different than the \
-                     one used in the CI (`{}`)",
-                    installed_version, v
-                );
-                eprintln!(
-                    "You can install this version using `npm update browser-ui-test` or by using \
-                     `npm install browser-ui-test@{}`",
-                    v,
-                );
-            }
-        }
-        Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
-    }
-}
-
 fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
     for entry in walkdir::WalkDir::new(path) {
         let entry = entry.ok()?;
@@ -71,27 +23,6 @@ fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
 fn main() -> Result<(), ()> {
     let config = Arc::new(Config::from_args(env::args().collect()));
 
-    // The goal here is to check if the necessary packages are installed, and if not, we
-    // panic.
-    match get_browser_ui_test_version(&config.npm) {
-        Some(version) => {
-            // We also check the version currently used in CI and emit a warning if it's not the
-            // same one.
-            compare_browser_ui_test_version(&version, &config.rust_src);
-        }
-        None => {
-            eprintln!(
-                r#"
-error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing.
-
-If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test`
-"#,
-            );
-
-            panic!("Cannot run rustdoc-gui tests");
-        }
-    }
-
     let src_path = config.rust_src.join("tests/rustdoc-gui/src");
     for entry in src_path.read_dir().expect("read_dir call failed") {
         if let Ok(entry) = entry {
@@ -134,16 +65,12 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse
         }
     }
 
-    let mut command = Command::new(&config.nodejs);
+    // FIXME(binarycat): once we get package.json in version control, this should be updated to install via that instead
+    let local_node_modules =
+        npm::install_one(&config.out_dir, &config.npm, "browser-ui-test", "0.21.1")
+            .expect("unable to install browser-ui-test");
 
-    if let Ok(current_dir) = env::current_dir() {
-        let local_node_modules = current_dir.join("node_modules");
-        if local_node_modules.exists() {
-            // Link the local node_modules if exists.
-            // This is useful when we run rustdoc-gui-test from outside of the source root.
-            env::set_var("NODE_PATH", local_node_modules);
-        }
-    }
+    let mut command = Command::new(&config.nodejs);
 
     command
         .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js"))
@@ -154,6 +81,12 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse
         .arg("--tests-folder")
         .arg(config.rust_src.join("tests/rustdoc-gui"));
 
+    if local_node_modules.exists() {
+        // Link the local node_modules if exists.
+        // This is useful when we run rustdoc-gui-test from outside of the source root.
+        command.env("NODE_PATH", local_node_modules);
+    }
+
     for file in &config.goml_files {
         command.arg("--file").arg(file);
     }
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index f70fc917770..0baa179e16b 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -28,7 +28,14 @@ function readFile(filePath) {
 }
 
 function contentToDiffLine(key, value) {
-    return `"${key}": "${value}",`;
+    if (typeof value === "object" && !Array.isArray(value) && value !== null) {
+        const out = Object.entries(value)
+            .filter(([subKey, _]) => ["path", "name"].includes(subKey))
+            .map(([subKey, subValue]) => `"${subKey}": ${JSON.stringify(subValue)}`)
+            .join(", ");
+        return `"${key}": ${out},`;
+    }
+    return `"${key}": ${JSON.stringify(value)},`;
 }
 
 function shouldIgnoreField(fieldName) {
@@ -37,47 +44,61 @@ function shouldIgnoreField(fieldName) {
         fieldName === "proposeCorrectionTo";
 }
 
+function valueMapper(key, testOutput) {
+    const isAlias = testOutput["is_alias"];
+    let value = testOutput[key];
+    // To make our life easier, if there is a "parent" type, we add it to the path.
+    if (key === "path") {
+        if (testOutput["parent"] !== undefined) {
+            if (value.length > 0) {
+                value += "::" + testOutput["parent"]["name"];
+            } else {
+                value = testOutput["parent"]["name"];
+            }
+        } else if (testOutput["is_alias"]) {
+            value = valueMapper(key, testOutput["original"]);
+        }
+    } else if (isAlias && key === "alias") {
+        value = testOutput["name"];
+    } else if (isAlias && ["name"].includes(key)) {
+        value = testOutput["original"][key];
+    }
+    return value;
+}
+
 // This function is only called when no matching result was found and therefore will only display
 // the diff between the two items.
-function betterLookingDiff(entry, data) {
+function betterLookingDiff(expected, testOutput) {
     let output = " {\n";
-    const spaces = "     ";
-    for (const key in entry) {
-        if (!Object.prototype.hasOwnProperty.call(entry, key)) {
+    const spaces = "    ";
+    for (const key in expected) {
+        if (!Object.prototype.hasOwnProperty.call(expected, key)) {
             continue;
         }
-        if (!data || !Object.prototype.hasOwnProperty.call(data, key)) {
-            output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n";
+        if (!testOutput || !Object.prototype.hasOwnProperty.call(testOutput, key)) {
+            output += "-" + spaces + contentToDiffLine(key, expected[key]) + "\n";
             continue;
         }
-        const value = data[key];
-        if (value !== entry[key]) {
-            output += "-" + spaces + contentToDiffLine(key, entry[key]) + "\n";
+        const value = valueMapper(key, testOutput);
+        if (value !== expected[key]) {
+            output += "-" + spaces + contentToDiffLine(key, expected[key]) + "\n";
             output += "+" + spaces + contentToDiffLine(key, value) + "\n";
         } else {
-            output += spaces + contentToDiffLine(key, value) + "\n";
+            output += spaces + " " + contentToDiffLine(key, value) + "\n";
         }
     }
     return output + " }";
 }
 
-function lookForEntry(entry, data) {
-    return data.findIndex(data_entry => {
+function lookForEntry(expected, testOutput) {
+    return testOutput.findIndex(testOutputEntry => {
         let allGood = true;
-        for (const key in entry) {
-            if (!Object.prototype.hasOwnProperty.call(entry, key)) {
+        for (const key in expected) {
+            if (!Object.prototype.hasOwnProperty.call(expected, key)) {
                 continue;
             }
-            let value = data_entry[key];
-            // To make our life easier, if there is a "parent" type, we add it to the path.
-            if (key === "path" && data_entry["parent"] !== undefined) {
-                if (value.length > 0) {
-                    value += "::" + data_entry["parent"]["name"];
-                } else {
-                    value = data_entry["parent"]["name"];
-                }
-            }
-            if (value !== entry[key]) {
+            const value = valueMapper(key, testOutputEntry);
+            if (value !== expected[key]) {
                 allGood = false;
                 break;
             }
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 1a3897b51cb..7084639aca9 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -1172,6 +1172,7 @@ pub(crate) fn format_trait(
         unreachable!();
     };
     let ast::Trait {
+        constness,
         is_auto,
         safety,
         ident,
@@ -1182,7 +1183,8 @@ pub(crate) fn format_trait(
 
     let mut result = String::with_capacity(128);
     let header = format!(
-        "{}{}{}trait ",
+        "{}{}{}{}trait ",
+        format_constness(constness),
         format_visibility(context, &item.vis),
         format_safety(safety),
         format_auto(is_auto),
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/issues.txt b/src/tools/tidy/src/issues.txt
index 8b57db23d01..77414bec82d 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1021,7 +1021,6 @@ ui/foreign/issue-91370-foreign-fn-block-impl.rs
 ui/foreign/issue-99276-same-type-lifetimes.rs
 ui/function-pointer/issue-102289.rs
 ui/functions-closures/closure-expected-type/issue-38714.rs
-ui/generic-associated-types/bugs/issue-100013.rs
 ui/generic-associated-types/bugs/issue-80626.rs
 ui/generic-associated-types/bugs/issue-87735.rs
 ui/generic-associated-types/bugs/issue-87755.rs
@@ -1099,7 +1098,6 @@ ui/generic-associated-types/issue-90729.rs
 ui/generic-associated-types/issue-91139.rs
 ui/generic-associated-types/issue-91883.rs
 ui/generic-associated-types/issue-92033.rs
-ui/generic-associated-types/issue-92096.rs
 ui/generic-associated-types/issue-92280.rs
 ui/generic-associated-types/issue-92954.rs
 ui/generic-associated-types/issue-93141.rs
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/src/tools/unicode-table-generator/Cargo.toml b/src/tools/unicode-table-generator/Cargo.toml
index f8a500922d0..3ca6e9e316f 100644
--- a/src/tools/unicode-table-generator/Cargo.toml
+++ b/src/tools/unicode-table-generator/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "unicode-table-generator"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
diff --git a/src/tools/unicode-table-generator/src/cascading_map.rs b/src/tools/unicode-table-generator/src/cascading_map.rs
index 1eb35e819c0..78a7bba3208 100644
--- a/src/tools/unicode-table-generator/src/cascading_map.rs
+++ b/src/tools/unicode-table-generator/src/cascading_map.rs
@@ -21,7 +21,7 @@ impl RawEmitter {
 
         let points = ranges
             .iter()
-            .flat_map(|r| (r.start..r.end).into_iter().collect::<Vec<u32>>())
+            .flat_map(|r| (r.start..r.end).collect::<Vec<u32>>())
             .collect::<Vec<u32>>();
 
         println!("there are {} points", points.len());
@@ -32,21 +32,20 @@ impl RawEmitter {
             // assert that there is no whitespace over the 0x3000 range.
             assert!(point <= 0x3000, "the highest unicode whitespace value has changed");
             let high_bytes = point as usize >> 8;
-            let codepoints = codepoints_by_high_bytes.entry(high_bytes).or_insert_with(Vec::new);
+            let codepoints = codepoints_by_high_bytes.entry(high_bytes).or_default();
             codepoints.push(point);
         }
 
         let mut bit_for_high_byte = 1u8;
         let mut arms = Vec::<String>::new();
 
-        let mut high_bytes: Vec<usize> =
-            codepoints_by_high_bytes.keys().map(|k| k.clone()).collect();
+        let mut high_bytes: Vec<usize> = codepoints_by_high_bytes.keys().copied().collect();
         high_bytes.sort();
         for high_byte in high_bytes {
             let codepoints = codepoints_by_high_bytes.get_mut(&high_byte).unwrap();
             if codepoints.len() == 1 {
                 let ch = codepoints.pop().unwrap();
-                arms.push(format!("{} => c as u32 == {:#04x}", high_byte, ch));
+                arms.push(format!("{high_byte} => c as u32 == {ch:#04x}"));
                 continue;
             }
             // more than 1 codepoint in this arm
@@ -54,8 +53,7 @@ impl RawEmitter {
                 map[(*codepoint & 0xff) as usize] |= bit_for_high_byte;
             }
             arms.push(format!(
-                "{} => WHITESPACE_MAP[c as usize & 0xff] & {} != 0",
-                high_byte, bit_for_high_byte
+                "{high_byte} => WHITESPACE_MAP[c as usize & 0xff] & {bit_for_high_byte} != 0"
             ));
             bit_for_high_byte <<= 1;
         }
@@ -68,7 +66,7 @@ impl RawEmitter {
         writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap();
         writeln!(&mut self.file, "    match c as u32 >> 8 {{").unwrap();
         for arm in arms {
-            writeln!(&mut self.file, "        {},", arm).unwrap();
+            writeln!(&mut self.file, "        {arm},").unwrap();
         }
         writeln!(&mut self.file, "        _ => false,").unwrap();
         writeln!(&mut self.file, "    }}").unwrap();
diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs
index 00241b7ee0e..9c6454492e7 100644
--- a/src/tools/unicode-table-generator/src/case_mapping.rs
+++ b/src/tools/unicode-table-generator/src/case_mapping.rs
@@ -9,7 +9,7 @@ const INDEX_MASK: u32 = 1 << 22;
 pub(crate) fn generate_case_mapping(data: &UnicodeData) -> String {
     let mut file = String::new();
 
-    write!(file, "const INDEX_MASK: u32 = 0x{:x};", INDEX_MASK).unwrap();
+    write!(file, "const INDEX_MASK: u32 = 0x{INDEX_MASK:x};").unwrap();
     file.push_str("\n\n");
     file.push_str(HEADER.trim_start());
     file.push('\n');
diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs
index 415db2c4dbc..6cdb82a87bd 100644
--- a/src/tools/unicode-table-generator/src/main.rs
+++ b/src/tools/unicode-table-generator/src/main.rs
@@ -160,15 +160,15 @@ fn load_data() -> UnicodeData {
                 .push(Codepoints::Single(row.codepoint));
         }
 
-        if let Some(mapped) = row.simple_lowercase_mapping {
-            if mapped != row.codepoint {
-                to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0));
-            }
+        if let Some(mapped) = row.simple_lowercase_mapping
+            && mapped != row.codepoint
+        {
+            to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0));
         }
-        if let Some(mapped) = row.simple_uppercase_mapping {
-            if mapped != row.codepoint {
-                to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0));
-            }
+        if let Some(mapped) = row.simple_uppercase_mapping
+            && mapped != row.codepoint
+        {
+            to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0));
         }
     }
 
@@ -196,12 +196,12 @@ fn load_data() -> UnicodeData {
                     .flat_map(|codepoints| match codepoints {
                         Codepoints::Single(c) => c
                             .scalar()
-                            .map(|ch| (ch as u32..ch as u32 + 1))
+                            .map(|ch| ch as u32..ch as u32 + 1)
                             .into_iter()
                             .collect::<Vec<_>>(),
                         Codepoints::Range(c) => c
                             .into_iter()
-                            .flat_map(|c| c.scalar().map(|ch| (ch as u32..ch as u32 + 1)))
+                            .flat_map(|c| c.scalar().map(|ch| ch as u32..ch as u32 + 1))
                             .collect::<Vec<_>>(),
                     })
                     .collect::<Vec<Range<u32>>>(),
@@ -236,7 +236,7 @@ fn main() {
     let ranges_by_property = &unicode_data.ranges;
 
     if let Some(path) = test_path {
-        std::fs::write(&path, generate_tests(&write_location, &ranges_by_property)).unwrap();
+        std::fs::write(&path, generate_tests(&write_location, ranges_by_property)).unwrap();
     }
 
     let mut total_bytes = 0;
@@ -246,9 +246,9 @@ fn main() {
 
         let mut emitter = RawEmitter::new();
         if property == &"White_Space" {
-            emit_whitespace(&mut emitter, &ranges);
+            emit_whitespace(&mut emitter, ranges);
         } else {
-            emit_codepoints(&mut emitter, &ranges);
+            emit_codepoints(&mut emitter, ranges);
         }
 
         modules.push((property.to_lowercase().to_string(), emitter.file));
@@ -288,7 +288,7 @@ fn main() {
         for line in contents.lines() {
             if !line.trim().is_empty() {
                 table_file.push_str("    ");
-                table_file.push_str(&line);
+                table_file.push_str(line);
             }
             table_file.push('\n');
         }
@@ -312,7 +312,7 @@ fn version() -> String {
     let start = readme.find(prefix).unwrap() + prefix.len();
     let end = readme.find(" of the Unicode Standard.").unwrap();
     let version =
-        readme[start..end].split('.').map(|v| v.parse::<u32>().expect(&v)).collect::<Vec<_>>();
+        readme[start..end].split('.').map(|v| v.parse::<u32>().expect(v)).collect::<Vec<_>>();
     let [major, minor, micro] = [version[0], version[1], version[2]];
 
     out.push_str(&format!("({major}, {minor}, {micro});\n"));
@@ -320,7 +320,7 @@ fn version() -> String {
 }
 
 fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String {
-    let pieces = values.into_iter().map(|b| format!("{:?}, ", b)).collect::<Vec<_>>();
+    let pieces = values.into_iter().map(|b| format!("{b:?}, ")).collect::<Vec<_>>();
     let mut out = String::new();
     let mut line = String::from("\n    ");
     for piece in pieces {
@@ -348,7 +348,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String
     s.push_str("\nfn main() {\n");
 
     for (property, ranges) in ranges {
-        s.push_str(&format!(r#"    println!("Testing {}");"#, property));
+        s.push_str(&format!(r#"    println!("Testing {property}");"#));
         s.push('\n');
         s.push_str(&format!("    {}_true();\n", property.to_lowercase()));
         s.push_str(&format!("    {}_false();\n", property.to_lowercase()));
@@ -373,7 +373,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String
         s.push_str("    }\n\n");
     }
 
-    s.push_str("}");
+    s.push('}');
     s
 }
 
@@ -388,7 +388,7 @@ fn generate_asserts(s: &mut String, property: &str, points: &[u32], truthy: bool
                 range.start,
             ));
         } else {
-            s.push_str(&format!("        for chn in {:?}u32 {{\n", range));
+            s.push_str(&format!("        for chn in {range:?}u32 {{\n"));
             s.push_str(&format!(
                 "            assert!({}unicode_data::{}::lookup(std::char::from_u32(chn).unwrap()), \"{{:?}}\", chn);\n",
                 if truthy { "" } else { "!" },
@@ -439,7 +439,7 @@ fn merge_ranges(ranges: &mut Vec<Range<u32>>) {
     let mut last_end = None;
     for range in ranges {
         if let Some(last) = last_end {
-            assert!(range.start > last, "{:?}", range);
+            assert!(range.start > last, "{range:?}");
         }
         last_end = Some(range.end);
     }
diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs
index ee94d3c93a6..e9e0efc4594 100644
--- a/src/tools/unicode-table-generator/src/raw_emitter.rs
+++ b/src/tools/unicode-table-generator/src/raw_emitter.rs
@@ -156,10 +156,10 @@ pub fn emit_codepoints(emitter: &mut RawEmitter, ranges: &[Range<u32>]) {
     emitter.blank_line();
 
     let mut bitset = emitter.clone();
-    let bitset_ok = bitset.emit_bitset(&ranges).is_ok();
+    let bitset_ok = bitset.emit_bitset(ranges).is_ok();
 
     let mut skiplist = emitter.clone();
-    skiplist.emit_skiplist(&ranges);
+    skiplist.emit_skiplist(ranges);
 
     if bitset_ok && bitset.bytes_used <= skiplist.bytes_used {
         *emitter = bitset;
@@ -174,7 +174,7 @@ pub fn emit_whitespace(emitter: &mut RawEmitter, ranges: &[Range<u32>]) {
     emitter.blank_line();
 
     let mut cascading = emitter.clone();
-    cascading.emit_cascading_map(&ranges);
+    cascading.emit_cascading_map(ranges);
     *emitter = cascading;
     emitter.desc = String::from("cascading");
 }
@@ -272,7 +272,7 @@ impl Canonicalized {
         // for canonical when possible.
         while let Some((&to, _)) = mappings
             .iter()
-            .find(|(&to, _)| to == 0)
+            .find(|&(&to, _)| to == 0)
             .or_else(|| mappings.iter().max_by_key(|m| m.1.len()))
         {
             // Get the mapping with the most entries. Currently, no mapping can
@@ -311,10 +311,9 @@ impl Canonicalized {
                     }
                 }
             }
-            assert!(
-                unique_mapping
-                    .insert(to, UniqueMapping::Canonical(canonical_words.len()))
-                    .is_none()
+            assert_eq!(
+                unique_mapping.insert(to, UniqueMapping::Canonical(canonical_words.len())),
+                None
             );
             canonical_words.push(to);
 
@@ -340,14 +339,10 @@ impl Canonicalized {
         // We'll probably always have some slack though so this loop will still
         // be needed.
         for &w in unique_words {
-            if !unique_mapping.contains_key(&w) {
-                assert!(
-                    unique_mapping
-                        .insert(w, UniqueMapping::Canonical(canonical_words.len()))
-                        .is_none()
-                );
+            unique_mapping.entry(w).or_insert_with(|| {
                 canonical_words.push(w);
-            }
+                UniqueMapping::Canonical(canonical_words.len())
+            });
         }
         assert_eq!(canonicalized_words.len() + canonical_words.len(), unique_words.len());
         assert_eq!(unique_mapping.len(), unique_words.len());
diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs
index f7d0775f7af..03688e0068b 100644
--- a/tests/assembly/cstring-merging.rs
+++ b/tests/assembly/cstring-merging.rs
@@ -2,7 +2,7 @@
 // other architectures (including ARM and x86-64) use the prefix `.Lanon.`
 //@ only-linux
 //@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -Copt-level=3
+//@ compile-flags: --crate-type=lib -Copt-level=3 -Cllvm-args=-enable-global-merge=0
 //@ edition: 2024
 
 use std::ffi::CStr;
diff --git a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs
index b3b623b509b..f9966a23446 100644
--- a/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs
+++ b/tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs
@@ -8,6 +8,14 @@
 //@ min-llvm-version: 21.0.0
 
 #![crate_type = "lib"]
+#![feature(no_core)]
+#![no_core]
+
+extern crate minicore;
+
+unsafe extern "C" {
+    safe fn add(x: i32, y: i32) -> i32;
+}
 
 pub fn add_one(x: i32) -> i32 {
     // CHECK-LABEL: __cfi__{{.*}}7add_one{{.*}}:
@@ -23,7 +31,7 @@ pub fn add_one(x: i32) -> i32 {
     // CHECK-NEXT:  nop
     // CHECK-NEXT:  nop
     // CHECK-NEXT:  mov ecx, 2628068948
-    x + 1
+    add(x, 1)
 }
 
 pub fn add_two(x: i32, _y: i32) -> i32 {
@@ -40,7 +48,7 @@ pub fn add_two(x: i32, _y: i32) -> i32 {
     // CHECK-NEXT:  nop
     // CHECK-NEXT:  nop
     // CHECK-NEXT:  mov edx, 2505940310
-    x + 2
+    add(x, 2)
 }
 
 pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
@@ -57,5 +65,5 @@ pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
     // CHECK-NEXT:  nop
     // CHECK-NEXT:  nop
     // CHECK-NEXT:  mov edx, 653723426
-    f(arg) + f(arg)
+    add(f(arg), f(arg))
 }
diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs
index f05ccfadc58..704e8026f3f 100644
--- a/tests/assembly/wasm_exceptions.rs
+++ b/tests/assembly/wasm_exceptions.rs
@@ -2,7 +2,6 @@
 //@ assembly-output: emit-asm
 //@ compile-flags: -C target-feature=+exception-handling
 //@ compile-flags: -C panic=unwind
-//@ compile-flags: -C llvm-args=-wasm-enable-eh
 
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
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/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs
new file mode 100644
index 00000000000..2097567f322
--- /dev/null
+++ b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs
@@ -0,0 +1,22 @@
+//! Make sure that line debuginfo of function parameters are correct even if
+//! they are not on the same line. Regression test for
+// <https://github.com/rust-lang/rust/issues/45010>.
+
+//@ compile-flags: -g -Copt-level=0
+
+#[rustfmt::skip] // Having parameters on different lines is crucial for this test.
+pub fn foo(
+    x_parameter_not_in_std: i32,
+    y_parameter_not_in_std: i32,
+) -> i32 {
+    x_parameter_not_in_std + y_parameter_not_in_std
+}
+
+fn main() {
+    foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`)
+}
+
+// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1,
+// CHECK-SAME: line: 9
+// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2,
+// CHECK-SAME: line: 10
diff --git a/tests/codegen/repeat-operand-zero-len.rs b/tests/codegen/repeat-operand-zero-len.rs
new file mode 100644
index 00000000000..b4cec42a07c
--- /dev/null
+++ b/tests/codegen/repeat-operand-zero-len.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes
+
+// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`.
+// It only applies when the resulting array is a ZST, so the test is written in
+// such a way as to keep MIR optimizations from seeing that fact and removing
+// the local and statement altogether. (At the time of writing, no other codegen
+// test hit that code path, nor did a stage 2 build of the compiler.)
+
+#![crate_type = "lib"]
+
+#[repr(transparent)]
+pub struct Wrapper<T, const N: usize>([T; N]);
+
+// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x)
+// CHECK-NEXT: start:
+// CHECK-NOT: alloca
+// CHECK-NEXT: ret void
+#[inline(never)]
+pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
+    Wrapper([x; N])
+}
+
+// CHECK-LABEL: @trigger_repeat_zero_len
+#[no_mangle]
+pub fn trigger_repeat_zero_len() -> Wrapper<u32, 0> {
+    // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4)
+    do_repeat(4)
+}
diff --git a/tests/codegen/repeat-operand-zst-elem.rs b/tests/codegen/repeat-operand-zst-elem.rs
new file mode 100644
index 00000000000..c3637759afa
--- /dev/null
+++ b/tests/codegen/repeat-operand-zst-elem.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes
+
+// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`.
+// It only applies when the resulting array is a ZST, so the test is written in
+// such a way as to keep MIR optimizations from seeing that fact and removing
+// the local and statement altogether. (At the time of writing, no other codegen
+// test hit that code path, nor did a stage 2 build of the compiler.)
+
+#![crate_type = "lib"]
+
+#[repr(transparent)]
+pub struct Wrapper<T, const N: usize>([T; N]);
+
+// CHECK-LABEL: define {{.+}}do_repeat{{.+}}()
+// CHECK-NEXT: start:
+// CHECK-NOT: alloca
+// CHECK-NEXT: ret void
+#[inline(never)]
+pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
+    Wrapper([x; N])
+}
+
+// CHECK-LABEL: @trigger_repeat_zst_elem
+#[no_mangle]
+pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> {
+    // CHECK: call void {{.+}}do_repeat{{.+}}()
+    do_repeat(())
+}
diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs
new file mode 100644
index 00000000000..2c8cdc919b8
--- /dev/null
+++ b/tests/codegen/sanitizer/kcfi/naked-function.rs
@@ -0,0 +1,47 @@
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+struct Thing;
+trait MyTrait {
+    #[unsafe(naked)]
+    extern "C" fn my_naked_function() {
+        // the real function is defined
+        // CHECK: .globl
+        // CHECK-SAME: my_naked_function
+        naked_asm!("ret")
+    }
+}
+impl MyTrait for Thing {}
+
+// the shim calls the real function
+// CHECK-LABEL: define
+// CHECK-SAME: my_naked_function
+// CHECK-SAME: reify.shim.fnptr
+
+// CHECK-LABEL: main
+#[unsafe(no_mangle)]
+pub fn main() {
+    // Trick the compiler into generating an indirect call.
+    const F: extern "C" fn() = Thing::my_naked_function;
+
+    // main calls the shim function
+    // CHECK: call void
+    // CHECK-SAME: my_naked_function
+    // CHECK-SAME: reify.shim.fnptr
+    (F)();
+}
+
+// CHECK: declare !kcfi_type
+// CHECK-SAME: my_naked_function
diff --git a/tests/crashes/117629.rs b/tests/crashes/117629.rs
index d8b5f328545..f63365395c6 100644
--- a/tests/crashes/117629.rs
+++ b/tests/crashes/117629.rs
@@ -3,8 +3,7 @@
 
 #![feature(const_trait_impl)]
 
-#[const_trait]
-trait Tr {
+const trait Tr {
     async fn ft1() {}
 }
 
diff --git a/tests/crashes/133275-1.rs b/tests/crashes/133275-1.rs
deleted file mode 100644
index 73c04f5d6e4..00000000000
--- a/tests/crashes/133275-1.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ known-bug: #133275
-#![feature(const_trait_impl)]
-#![feature(associated_type_defaults)]
-
-#[const_trait]
-trait Foo3<T>
-where
-    Self::Baz: Clone,
-{
-    type Baz = T;
-}
-
-pub fn main() {}
diff --git a/tests/crashes/133275-2.rs b/tests/crashes/133275-2.rs
deleted file mode 100644
index a774b3cdb69..00000000000
--- a/tests/crashes/133275-2.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #133275
-#![feature(const_trait_impl)]
-#[const_trait]
-pub trait Owo<X = <IntEnum as Uwu>::T> {}
-
-#[const_trait]
-trait Foo3<T>
-where
-    Self::Bar: Clone,
-    Self::Baz: Clone,
-{
-    type Bar = Vec<Self::Baz>;
-    type Baz = T;
-    //~^ ERROR the trait bound `T: Clone` is not satisfied
-}
diff --git a/tests/crashes/const_mut_ref_check_bypass.rs b/tests/crashes/const_mut_ref_check_bypass.rs
deleted file mode 100644
index 6234536c72b..00000000000
--- a/tests/crashes/const_mut_ref_check_bypass.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Version of `tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs` without the flag that
-// suppresses the ICE.
-//@ known-bug: #129233
-#![feature(core_intrinsics)]
-#![feature(const_heap)]
-#![feature(const_mut_refs)]
-use std::intrinsics;
-
-const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
-
-fn main() {}
diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs
index 892b91a5414..33cbefbf053 100644
--- a/tests/mir-opt/const_prop/transmute.rs
+++ b/tests/mir-opt/const_prop/transmute.rs
@@ -56,7 +56,7 @@ pub unsafe fn undef_union_as_integer() -> u32 {
 pub unsafe fn unreachable_direct() -> ! {
     // CHECK-LABEL: fn unreachable_direct(
     // CHECK: = const ();
-    // CHECK: = const () as Never (Transmute);
+    // CHECK: = const ZeroSized: Never;
     let x: Never = unsafe { transmute(()) };
     match x {}
 }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
index 3364782022d..5aeb55a5a6a 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
@@ -15,7 +15,7 @@
 -         _2 = ();
 -         _1 = move _2 as Never (Transmute);
 +         _2 = const ();
-+         _1 = const () as Never (Transmute);
++         _1 = const ZeroSized: Never;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
index 3364782022d..5aeb55a5a6a 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
@@ -15,7 +15,7 @@
 -         _2 = ();
 -         _1 = move _2 as Never (Transmute);
 +         _2 = const ();
-+         _1 = const () as Never (Transmute);
++         _1 = const ZeroSized: Never;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff
index 770c6730775..ffe4a0272b4 100644
--- a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-abort.diff
@@ -18,7 +18,8 @@
   
       bb0: {
           _4 = copy _1 as *const T (PtrToPtr);
-          _5 = PtrMetadata(copy _4);
+-         _5 = PtrMetadata(copy _4);
++         _5 = const ();
           _6 = copy _1 as *const (&A, [T]) (PtrToPtr);
 -         _7 = PtrMetadata(copy _6);
 +         _7 = PtrMetadata(copy _1);
diff --git a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff
index 770c6730775..ffe4a0272b4 100644
--- a/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.generic_cast_metadata.GVN.panic-unwind.diff
@@ -18,7 +18,8 @@
   
       bb0: {
           _4 = copy _1 as *const T (PtrToPtr);
-          _5 = PtrMetadata(copy _4);
+-         _5 = PtrMetadata(copy _4);
++         _5 = const ();
           _6 = copy _1 as *const (&A, [T]) (PtrToPtr);
 -         _7 = PtrMetadata(copy _6);
 +         _7 = PtrMetadata(copy _1);
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 6ef320c90de..5d348bc3c1e 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -869,7 +869,7 @@ fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A,
 
             // Metadata usize -> (), do not optimize.
             // CHECK: [[T:_.+]] = copy _1 as
-            // CHECK-NEXT: PtrMetadata(copy [[T]])
+            // CHECK-NEXT: const ();
             let t1 = CastPtrToPtr::<_, *const T>(ps);
             let m1 = PtrMetadata(t1);
 
diff --git a/tests/mir-opt/inline/cycle.rs b/tests/mir-opt/inline/cycle.rs
index 383d0796a88..6e0f45bb3e9 100644
--- a/tests/mir-opt/inline/cycle.rs
+++ b/tests/mir-opt/inline/cycle.rs
@@ -13,7 +13,7 @@ fn f(g: impl Fn()) {
 #[inline(always)]
 fn g() {
     // CHECK-LABEL: fn g(
-    // CHECK-NOT: (inlined f::<fn() {main}>)
+    // CHECK-NOT: inlined
     f(main);
 }
 
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/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
index 3b58f1d61f4..8c5fbda6392 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
@@ -109,7 +109,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb4: {
-        StorageLive(_15);
         _14 = &mut _13;
         _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind: bb11];
     }
@@ -120,7 +119,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb6: {
-        StorageDead(_15);
         StorageDead(_13);
         drop(_2) -> [return: bb7, unwind continue];
     }
@@ -135,14 +133,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         StorageLive(_19);
         _19 = &_2;
         StorageLive(_20);
-        _20 = (copy _17, copy _18);
+        _20 = copy ((_15 as Some).0: (usize, &T));
         _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11];
     }
 
     bb9: {
         StorageDead(_20);
         StorageDead(_19);
-        StorageDead(_15);
         goto -> bb4;
     }
 
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/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
index 5ce815b9aed..464208f989e 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
@@ -4,7 +4,7 @@ error: `[const]` is not allowed here
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> const-super-trait.rs:7:1
    |
 LL | trait Bar: ~const Foo {}
@@ -30,24 +30,24 @@ LL | const fn foo<T: ~const Bar>(x: &T) {
    = 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: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> const-super-trait.rs:7:12
    |
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^ can't be applied to `Foo`
    |
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> const-super-trait.rs:9:17
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
    |                 ^^^^^^ can't be applied to `Bar`
    |
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: ~const Foo {}
    | ++++++++++++++
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
index ef764a62b06..569e559186f 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
@@ -4,30 +4,30 @@ error: `[const]` is not allowed here
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> const-super-trait.rs:7:1
    |
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> const-super-trait.rs:7:12
    |
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^ can't be applied to `Foo`
    |
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> const-super-trait.rs:9:17
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
    |                 ^^^^^^ can't be applied to `Bar`
    |
-help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: ~const Foo {}
    | ++++++++++++++
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
index 3dc147e076f..694e06fb6ea 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
@@ -4,7 +4,7 @@ error: `[const]` is not allowed here
 7 | trait Bar: ~const Foo {}
   |            ^^^^^^
   |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
  --> const-super-trait.rs:7:1
   |
 7 | trait Bar: ~const Foo {}
@@ -26,25 +26,25 @@ error[E0658]: const trait impls are experimental
   |
   = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
  --> const-super-trait.rs:7:12
   |
 7 | trait Bar: ~const Foo {}
   |            ^^^^^^ can't be applied to `Foo`
   |
-note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Foo` can't be used with `[const]` because it isn't `const`
  --> const-super-trait.rs:3:1
   |
 3 | trait Foo {
   | ^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
  --> const-super-trait.rs:9:17
   |
 9 | const fn foo<T: ~const Bar>(x: &T) {
   |                 ^^^^^^ can't be applied to `Bar`
   |
-note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Bar` can't be used with `[const]` because it isn't `const`
  --> const-super-trait.rs:7:1
   |
 7 | trait Bar: ~const Foo {}
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
index 2cdeb277ca4..2109f0deb72 100644
--- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
@@ -4,7 +4,7 @@ error: `[const]` is not allowed here
 7 | trait Bar: ~const Foo {}
   |            ^^^^^^
   |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
  --> const-super-trait.rs:7:1
   |
 7 | trait Bar: ~const Foo {}
@@ -16,25 +16,25 @@ error[E0554]: `#![feature]` may not be used on the NIGHTLY release channel
 1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))]
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
  --> const-super-trait.rs:7:12
   |
 7 | trait Bar: ~const Foo {}
   |            ^^^^^^ can't be applied to `Foo`
   |
-note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Foo` can't be used with `[const]` because it isn't `const`
  --> const-super-trait.rs:3:1
   |
 3 | trait Foo {
   | ^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
  --> const-super-trait.rs:9:17
   |
 9 | const fn foo<T: ~const Bar>(x: &T) {
   |                 ^^^^^^ can't be applied to `Bar`
   |
-note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Bar` can't be used with `[const]` because it isn't `const`
  --> const-super-trait.rs:7:1
   |
 7 | trait Bar: ~const Foo {}
diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs
index 09a7c27a106..729b71457e9 100644
--- a/tests/run-make/const-trait-stable-toolchain/rmake.rs
+++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs
@@ -11,9 +11,7 @@ fn main() {
         .env("RUSTC_BOOTSTRAP", "-1")
         .cfg("feature_enabled")
         .run_fail()
-        .assert_stderr_not_contains(
-            "as `#[const_trait]` to allow it to have `const` implementations",
-        )
+        .assert_stderr_not_contains("as `const` to allow it to have `const` implementations")
         .stderr_utf8();
     diff()
         .expected_file("const-super-trait-stable-enabled.stderr")
@@ -29,7 +27,7 @@ fn main() {
         .ui_testing()
         .run_fail()
         .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark")
-        .assert_stderr_contains("as `#[const_trait]` to allow it to have `const` implementations")
+        .assert_stderr_contains("as `const` to allow it to have `const` implementations")
         .stderr_utf8();
     diff()
         .expected_file("const-super-trait-nightly-enabled.stderr")
@@ -40,9 +38,7 @@ fn main() {
         .env("RUSTC_BOOTSTRAP", "-1")
         .run_fail()
         .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark")
-        .assert_stderr_not_contains(
-            "as `#[const_trait]` to allow it to have `const` implementations",
-        )
+        .assert_stderr_not_contains("as `const` to allow it to have `const` implementations")
         .stderr_utf8();
     diff()
         .expected_file("const-super-trait-stable-disabled.stderr")
diff --git a/tests/run-make/export-executable-symbols/rmake.rs b/tests/run-make/export-executable-symbols/rmake.rs
index 884c7362822..aa130b0855b 100644
--- a/tests/run-make/export-executable-symbols/rmake.rs
+++ b/tests/run-make/export-executable-symbols/rmake.rs
@@ -4,20 +4,22 @@
 // symbol.
 // See https://github.com/rust-lang/rust/pull/85673
 
-//@ only-unix
-// Reason: the export-executable-symbols flag only works on Unix
-// due to hardcoded platform-specific implementation
-// (See #85673)
-//@ ignore-cross-compile
 //@ ignore-wasm
+//@ ignore-cross-compile
 
-use run_make_support::{bin_name, llvm_readobj, rustc};
+use run_make_support::object::Object;
+use run_make_support::{bin_name, is_darwin, object, rustc};
 
 fn main() {
-    rustc().arg("-Zexport-executable-symbols").input("main.rs").crate_type("bin").run();
-    llvm_readobj()
-        .symbols()
-        .input(bin_name("main"))
-        .run()
-        .assert_stdout_contains("exported_symbol");
+    rustc()
+        .arg("-Ctarget-feature=-crt-static")
+        .arg("-Zexport-executable-symbols")
+        .input("main.rs")
+        .crate_type("bin")
+        .run();
+    let name: &[u8] = if is_darwin() { b"_exported_symbol" } else { b"exported_symbol" };
+    let contents = std::fs::read(bin_name("main")).unwrap();
+    let object = object::File::parse(contents.as_slice()).unwrap();
+    let found = object.exports().unwrap().iter().any(|x| x.name() == name);
+    assert!(found);
 }
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/run-make/mte-ffi/bar.h b/tests/run-make/mte-ffi/bar.h
index 9b030c618d1..a2292ae02a3 100644
--- a/tests/run-make/mte-ffi/bar.h
+++ b/tests/run-make/mte-ffi/bar.h
@@ -1,5 +1,3 @@
-// FIXME(#141600) the mte-ffi test doesn't fail in aarch64-gnu
-
 #ifndef __BAR_H
 #define __BAR_H
 
diff --git a/tests/run-make/mte-ffi/bar_float.c b/tests/run-make/mte-ffi/bar_float.c
index acc2f5d9266..a1590f62765 100644
--- a/tests/run-make/mte-ffi/bar_float.c
+++ b/tests/run-make/mte-ffi/bar_float.c
@@ -3,9 +3,9 @@
 #include <stdint.h>
 #include "bar.h"
 
-extern void foo(float*);
+extern void foo(char*);
 
-void bar(float *ptr) {
+void bar(char *ptr) {
     if (((uintptr_t)ptr >> 56) != 0x1f) {
         fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
         exit(1);
diff --git a/tests/run-make/mte-ffi/bar_int.c b/tests/run-make/mte-ffi/bar_int.c
index c92e765302c..d1c79e95dc9 100644
--- a/tests/run-make/mte-ffi/bar_int.c
+++ b/tests/run-make/mte-ffi/bar_int.c
@@ -5,7 +5,7 @@
 
 extern void foo(unsigned int *);
 
-void bar(unsigned int *ptr) {
+void bar(char *ptr) {
     if (((uintptr_t)ptr >> 56) != 0x1f) {
         fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
         exit(1);
diff --git a/tests/run-make/mte-ffi/bar_string.c b/tests/run-make/mte-ffi/bar_string.c
index 8e1202f6fd1..5669ffd6695 100644
--- a/tests/run-make/mte-ffi/bar_string.c
+++ b/tests/run-make/mte-ffi/bar_string.c
@@ -1,7 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
-#include <string.h>
 #include "bar.h"
 
 extern void foo(char*);
@@ -33,7 +32,7 @@ int main(void)
 
     // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be),
     // and a different value in the ignored top 4 bits.
-    ptr = (char *)((uintptr_t)ptr | 0x1fl << 56);
+    ptr = (unsigned int *)((uintptr_t)ptr | 0x1fl << 56);
 
     if (mte_enabled()) {
         set_tag(ptr);
diff --git a/tests/run-make/mte-ffi/rmake.rs b/tests/run-make/mte-ffi/rmake.rs
index a8da0dc0ee0..71d8318d946 100644
--- a/tests/run-make/mte-ffi/rmake.rs
+++ b/tests/run-make/mte-ffi/rmake.rs
@@ -2,6 +2,13 @@
 //! FFI boundaries (C <-> Rust). This test does not require MTE: whilst the test will use MTE if
 //! available, if it is not, arbitrary tag bits are set using TBI.
 
+//@ ignore-test (FIXME #141600)
+//
+// FIXME(#141600): this test is broken in two ways:
+// 1. This test triggers `-Wincompatible-pointer-types` on GCC 14.
+// 2. This test requires ARMv8.5+ w/ MTE extensions enabled, but GHA CI runner hardware do not have
+//    this enabled.
+
 //@ only-aarch64-unknown-linux-gnu
 // Reason: this test is only valid for AArch64 with `gcc`. The linker must be explicitly specified
 // when cross-compiling, so it is limited to `aarch64-unknown-linux-gnu`.
diff --git a/tests/run-make/option-output-no-space/main.rs b/tests/run-make/option-output-no-space/main.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/option-output-no-space/main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/option-output-no-space/rmake.rs b/tests/run-make/option-output-no-space/rmake.rs
new file mode 100644
index 00000000000..2c42f15aa89
--- /dev/null
+++ b/tests/run-make/option-output-no-space/rmake.rs
@@ -0,0 +1,95 @@
+// This test is to check if the warning is emitted when no space
+// between `-o` and arg is applied, see issue #142812
+
+//@ ignore-cross-compile
+use run_make_support::rustc;
+
+fn main() {
+    // test fake args
+    rustc()
+        .input("main.rs")
+        .arg("-optimize")
+        .run()
+        .assert_stderr_contains(
+            "warning: option `-o` has no space between flag name and value, which can be confusing",
+        )
+        .assert_stderr_contains(
+            "note: output filename `-o ptimize` is applied instead of a flag named `optimize`",
+        );
+    rustc()
+        .input("main.rs")
+        .arg("-o0")
+        .run()
+        .assert_stderr_contains(
+            "warning: option `-o` has no space between flag name and value, which can be confusing",
+        )
+        .assert_stderr_contains(
+            "note: output filename `-o 0` is applied instead of a flag named `o0`",
+        );
+    rustc().input("main.rs").arg("-o1").run();
+    // test real args by iter optgroups
+    rustc()
+        .input("main.rs")
+        .arg("-out-dir")
+        .run()
+        .assert_stderr_contains(
+            "warning: option `-o` has no space between flag name and value, which can be confusing",
+        )
+        .assert_stderr_contains(
+            "note: output filename `-o ut-dir` is applied instead of a flag named `out-dir`",
+        )
+        .assert_stderr_contains(
+            "help: insert a space between `-o` and `ut-dir` if this is intentional: `-o ut-dir`",
+        );
+    // test real args by iter CG_OPTIONS
+    rustc()
+        .input("main.rs")
+        .arg("-opt_level")
+        .run()
+        .assert_stderr_contains(
+            "warning: option `-o` has no space between flag name and value, which can be confusing",
+        )
+        .assert_stderr_contains(
+            "note: output filename `-o pt_level` is applied instead of a flag named `opt_level`",
+        )
+        .assert_stderr_contains(
+            "help: insert a space between `-o` and `pt_level` if this is intentional: `-o pt_level`"
+        );
+    // separater in-sensitive
+    rustc()
+        .input("main.rs")
+        .arg("-opt-level")
+        .run()
+        .assert_stderr_contains(
+            "warning: option `-o` has no space between flag name and value, which can be confusing",
+        )
+        .assert_stderr_contains(
+            "note: output filename `-o pt-level` is applied instead of a flag named `opt-level`",
+        )
+        .assert_stderr_contains(
+            "help: insert a space between `-o` and `pt-level` if this is intentional: `-o pt-level`"
+        );
+    rustc()
+        .input("main.rs")
+        .arg("-overflow-checks")
+        .run()
+        .assert_stderr_contains(
+            "warning: option `-o` has no space between flag name and value, which can be confusing",
+        )
+        .assert_stderr_contains(
+            "note: output filename `-o verflow-checks` \
+            is applied instead of a flag named `overflow-checks`",
+        )
+        .assert_stderr_contains(
+            "help: insert a space between `-o` and `verflow-checks` \
+            if this is intentional: `-o verflow-checks`",
+        );
+
+    // No warning for Z_OPTIONS
+    rustc().input("main.rs").arg("-oom").run().assert_stderr_equals("");
+
+    // test no warning when there is space between `-o` and arg
+    rustc().input("main.rs").arg("-o").arg("ptimize").run().assert_stderr_equals("");
+    rustc().input("main.rs").arg("--out-dir").arg("xxx").run().assert_stderr_equals("");
+    rustc().input("main.rs").arg("-o").arg("out-dir").run().assert_stderr_equals("");
+}
diff --git a/tests/rustdoc-js-std/alias-lev.js b/tests/rustdoc-js-std/alias-lev.js
new file mode 100644
index 00000000000..17f3dc25d76
--- /dev/null
+++ b/tests/rustdoc-js-std/alias-lev.js
@@ -0,0 +1,11 @@
+// This test ensures that aliases are also allowed to be partially matched.
+
+// ignore-order
+
+const EXPECTED = {
+    // The full alias name is `getcwd`.
+    'query': 'getcw',
+    'others': [
+        { 'path': 'std::env', 'name': 'current_dir', 'alias': 'getcwd' },
+    ],
+};
diff --git a/tests/rustdoc-js/non-english-identifier.js b/tests/rustdoc-js/non-english-identifier.js
index f2180b4c755..3d50bd3ee90 100644
--- a/tests/rustdoc-js/non-english-identifier.js
+++ b/tests/rustdoc-js/non-english-identifier.js
@@ -115,11 +115,10 @@ const EXPECTED = [
         query: '加法',
         others: [
             {
-                name: "add",
+                name: "加法",
                 path: "non_english_identifier",
-                is_alias: true,
-                alias: "加法",
-                href: "../non_english_identifier/macro.add.html"
+                href: "../non_english_identifier/trait.加法.html",
+                desc: "Add"
             },
             {
                 name: "add",
@@ -129,11 +128,13 @@ const EXPECTED = [
                 href: "../non_english_identifier/fn.add.html"
             },
             {
-                name: "加法",
+                name: "add",
                 path: "non_english_identifier",
-                href: "../non_english_identifier/trait.加法.html",
-                desc: "Add"
-            }],
+                is_alias: true,
+                alias: "加法",
+                href: "../non_english_identifier/macro.add.html"
+            },
+        ],
         in_args: [{
             name: "加上",
             path: "non_english_identifier::加法",
diff --git a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr
index 85c9516236c..9d3ce5e63ef 100644
--- a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr
+++ b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr
@@ -4,13 +4,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module
 LL | #[doc(alias = "foo")]
    |       ^^^^^^^^^^^^^
 
-error: `#[doc(alias = "...")]` isn't allowed on implementation block
+error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block
   --> $DIR/check-doc-alias-attr-location.rs:10:7
    |
 LL | #[doc(alias = "bar")]
    |       ^^^^^^^^^^^^^
 
-error: `#[doc(alias = "...")]` isn't allowed on implementation block
+error: `#[doc(alias = "...")]` isn't allowed on trait implementation block
   --> $DIR/check-doc-alias-attr-location.rs:16:7
    |
 LL | #[doc(alias = "foobar")]
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/asm/naked-function-shim.rs b/tests/ui/asm/naked-function-shim.rs
new file mode 100644
index 00000000000..4694d0cd963
--- /dev/null
+++ b/tests/ui/asm/naked-function-shim.rs
@@ -0,0 +1,31 @@
+// The indirect call will generate a shim that then calls the actual function. Test that
+// this is handled correctly. See also https://github.com/rust-lang/rust/issues/143266.
+
+//@ build-pass
+//@ add-core-stubs
+//@ revisions: aarch64 x86_64
+//@ [aarch64] compile-flags: --target aarch64-unknown-none
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [x86_64] compile-flags: --target x86_64-unknown-none
+//@ [x86_64] needs-llvm-components: x86
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+trait MyTrait {
+    #[unsafe(naked)]
+    extern "C" fn foo(&self) {
+        naked_asm!("ret")
+    }
+}
+
+impl MyTrait for i32 {}
+
+fn main() {
+    let x: extern "C" fn(&_) = <dyn MyTrait as MyTrait>::foo;
+    x(&1);
+}
diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr
index 915b54b3fc2..2571c8fa989 100644
--- a/tests/ui/asm/naked-invalid-attr.stderr
+++ b/tests/ui/asm/naked-invalid-attr.stderr
@@ -8,7 +8,7 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]`
   --> $DIR/naked-invalid-attr.rs:56:3
    |
 LL | #[::a]
-   |   ^^^ the `{{root}}::a` attribute is incompatible with `#[unsafe(naked)]`
+   |   ^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]`
 ...
 LL | #[unsafe(naked)]
    | ---------------- function marked with `#[unsafe(naked)]` here
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/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr
index b50e353b698..58a5b0b79c4 100644
--- a/tests/ui/async-await/async-closures/def-path.stderr
+++ b/tests/ui/async-await/async-closures/def-path.stderr
@@ -5,11 +5,11 @@ LL |     let x = async || {};
    |                      -- the expected `async` closure body
 LL |
 LL |     let () = x();
-   |         ^^   --- this expression has type `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}`
+   |         ^^   --- this expression has type `{static main::{closure#0}::{closure#0}<?16t> upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}`
    |         |
    |         expected `async` closure body, found `()`
    |
-   = note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}`
+   = note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?16t> upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}`
                          found unit type `()`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/async-await/async-drop/foreign-fundamental.rs b/tests/ui/async-await/async-drop/foreign-fundamental.rs
new file mode 100644
index 00000000000..1c192fccd9f
--- /dev/null
+++ b/tests/ui/async-await/async-drop/foreign-fundamental.rs
@@ -0,0 +1,21 @@
+//@ edition: 2018
+
+#![feature(async_drop)]
+//~^ WARN the feature `async_drop` is incomplete
+
+use std::future::AsyncDrop;
+use std::pin::Pin;
+
+struct Foo;
+
+impl AsyncDrop for &Foo {
+    //~^ ERROR the `AsyncDrop` trait may only be implemented for
+    async fn drop(self: Pin<&mut Self>) {}
+}
+
+impl AsyncDrop for Pin<Foo> {
+    //~^ ERROR the `AsyncDrop` trait may only be implemented for
+    async fn drop(self: Pin<&mut Self>) {}
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-drop/foreign-fundamental.stderr b/tests/ui/async-await/async-drop/foreign-fundamental.stderr
new file mode 100644
index 00000000000..7b52329ac99
--- /dev/null
+++ b/tests/ui/async-await/async-drop/foreign-fundamental.stderr
@@ -0,0 +1,24 @@
+warning: the feature `async_drop` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/foreign-fundamental.rs:3:12
+   |
+LL | #![feature(async_drop)]
+   |            ^^^^^^^^^^
+   |
+   = note: see issue #126482 <https://github.com/rust-lang/rust/issues/126482> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0120]: the `AsyncDrop` trait may only be implemented for local structs, enums, and unions
+  --> $DIR/foreign-fundamental.rs:11:20
+   |
+LL | impl AsyncDrop for &Foo {
+   |                    ^^^^ must be a struct, enum, or union in the current crate
+
+error[E0120]: the `AsyncDrop` trait may only be implemented for local structs, enums, and unions
+  --> $DIR/foreign-fundamental.rs:16:20
+   |
+LL | impl AsyncDrop for Pin<Foo> {
+   |                    ^^^^^^^^ must be a struct, enum, or union in the current crate
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0120`.
diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr
index 0d3ee8a9377..d5560bf8920 100644
--- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
+++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr
@@ -1,9 +1,7 @@
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5
    |
 LL | /     send(async {
-LL | |
-LL | |
 LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
 LL | |     });
    | |______^ implementation of `FnOnce` is not general enough
@@ -12,11 +10,9 @@ LL | |     });
    = note: ...but it actually implements `FnOnce<(&(),)>`
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5
    |
 LL | /     send(async {
-LL | |
-LL | |
 LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
 LL | |     });
    | |______^ implementation of `FnOnce` is not general enough
diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs
index e6c295405e2..16f929331cb 100644
--- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs
+++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs
@@ -1,5 +1,9 @@
 //@ incremental
 //@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
 
 use std::future::*;
 use std::marker::PhantomData;
@@ -96,8 +100,6 @@ impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> {
 
 fn main() {
     send(async {
-        //~^ ERROR implementation of `FnOnce` is not general enough
-        //~| ERROR implementation of `FnOnce` is not general enough
         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
     });
 }
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr
new file mode 100644
index 00000000000..b298a3bf215
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr
@@ -0,0 +1,38 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-auto-trait-1.rs:37:5
+   |
+LL | /     async {
+LL | |         let _y = &();
+LL | |         let _x = filter(FilterMap {
+LL | |             f: || async move { *_y },
+...  |
+LL | |         drop(_x);
+LL | |     }
+   | |_____^ one type is more general than the other
+   |
+   = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}`
+              found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}`
+   = note: no two async blocks, even if identical, have the same type
+   = help: consider pinning your async block and casting it to a trait object
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-auto-trait-1.rs:37:5
+   |
+LL | /     async {
+LL | |         let _y = &();
+LL | |         let _x = filter(FilterMap {
+LL | |             f: || async move { *_y },
+...  |
+LL | |         drop(_x);
+LL | |     }
+   | |_____^ one type is more general than the other
+   |
+   = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}`
+              found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}`
+   = note: no two async blocks, even if identical, have the same type
+   = help: consider pinning your async block and casting it to a trait object
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-1.rs b/tests/ui/async-await/higher-ranked-auto-trait-1.rs
new file mode 100644
index 00000000000..740f7e29245
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-1.rs
@@ -0,0 +1,48 @@
+// Repro for <https://github.com/rust-lang/rust/issues/79648#issuecomment-749127947>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::future::Future;
+use std::marker::PhantomData;
+
+trait Stream {
+    type Item;
+}
+
+struct Filter<St: Stream> {
+    pending_item: St::Item,
+}
+
+fn filter<St: Stream>(_: St) -> Filter<St> {
+    unimplemented!();
+}
+
+struct FilterMap<Fut, F> {
+    f: F,
+    pending: PhantomData<Fut>,
+}
+
+impl<Fut, F> Stream for FilterMap<Fut, F>
+where
+    F: FnMut() -> Fut,
+    Fut: Future,
+{
+    type Item = ();
+}
+
+pub fn get_foo() -> impl Future + Send {
+    async {
+        let _y = &();
+        let _x = filter(FilterMap {
+            f: || async move { *_y },
+            pending: PhantomData,
+        });
+        async {}.await;
+        drop(_x);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr
new file mode 100644
index 00000000000..6fcf1b1eac1
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr
@@ -0,0 +1,21 @@
+error: implementation of `Foo` is not general enough
+  --> $DIR/higher-ranked-auto-trait-10.rs:32:5
+   |
+LL |     Box::new(async move { get_foo(x).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/higher-ranked-auto-trait-10.rs:32:5
+   |
+LL |     Box::new(async move { get_foo(x).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr
new file mode 100644
index 00000000000..6fcf1b1eac1
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr
@@ -0,0 +1,21 @@
+error: implementation of `Foo` is not general enough
+  --> $DIR/higher-ranked-auto-trait-10.rs:32:5
+   |
+LL |     Box::new(async move { get_foo(x).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/higher-ranked-auto-trait-10.rs:32:5
+   |
+LL |     Box::new(async move { get_foo(x).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.rs b/tests/ui/async-await/higher-ranked-auto-trait-10.rs
new file mode 100644
index 00000000000..4bfa27961ab
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-10.rs
@@ -0,0 +1,35 @@
+// Repro for <https://github.com/rust-lang/rust/issues/92415#issue-1090723521>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] known-bug: unknown
+//@[no_assumptions] known-bug: #110338
+
+use std::any::Any;
+use std::future::Future;
+
+trait Foo<'a>: Sized {
+    type Error;
+    fn foo(x: &'a str) -> Result<Self, Self::Error>;
+}
+
+impl<'a> Foo<'a> for &'a str {
+    type Error = ();
+
+    fn foo(x: &'a str) -> Result<Self, Self::Error> {
+        Ok(x)
+    }
+}
+
+async fn get_foo<'a, T>(x: &'a str) -> Result<T, <T as Foo<'a>>::Error>
+where
+    T: Foo<'a>,
+{
+    Foo::foo(x)
+}
+
+fn bar<'a>(x: &'a str) -> Box<dyn Future<Output = Result<&'a str, ()>> + Send + 'a> {
+    Box::new(async move { get_foo(x).await })
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr
new file mode 100644
index 00000000000..d39843f628c
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/higher-ranked-auto-trait-11.rs:27:9
+   |
+LL | impl<'a, T> Foo<'a> for MyType<T>
+   |      -- lifetime `'a` defined here
+...
+LL |         Box::pin(async move { <T as Foo<'a>>::foo().await })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'a` must outlive `'static`
+
+error: implementation of `Send` is not general enough
+  --> $DIR/higher-ranked-auto-trait-11.rs:27:9
+   |
+LL |         Box::pin(async move { <T as Foo<'a>>::foo().await })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
+   |
+   = note: `Send` would have to be implemented for the type `<T as Foo<'0>>::Future`, for any lifetime `'0`...
+   = note: ...but `Send` is actually implemented for the type `<T as Foo<'1>>::Future`, for some specific lifetime `'1`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr
new file mode 100644
index 00000000000..d39843f628c
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/higher-ranked-auto-trait-11.rs:27:9
+   |
+LL | impl<'a, T> Foo<'a> for MyType<T>
+   |      -- lifetime `'a` defined here
+...
+LL |         Box::pin(async move { <T as Foo<'a>>::foo().await })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ coercion requires that `'a` must outlive `'static`
+
+error: implementation of `Send` is not general enough
+  --> $DIR/higher-ranked-auto-trait-11.rs:27:9
+   |
+LL |         Box::pin(async move { <T as Foo<'a>>::foo().await })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
+   |
+   = note: `Send` would have to be implemented for the type `<T as Foo<'0>>::Future`, for any lifetime `'0`...
+   = note: ...but `Send` is actually implemented for the type `<T as Foo<'1>>::Future`, for some specific lifetime `'1`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-11.rs b/tests/ui/async-await/higher-ranked-auto-trait-11.rs
new file mode 100644
index 00000000000..3aebdd8224d
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-11.rs
@@ -0,0 +1,31 @@
+// Repro for <https://github.com/rust-lang/rust/issues/60658#issuecomment-1509321859>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] known-bug: unknown
+//@[no_assumptions] known-bug: #110338
+
+use core::pin::Pin;
+use std::future::Future;
+
+pub trait Foo<'a> {
+    type Future: Future<Output = ()>;
+
+    fn foo() -> Self::Future;
+}
+
+struct MyType<T>(T);
+
+impl<'a, T> Foo<'a> for MyType<T>
+where
+    T: Foo<'a>,
+    T::Future: Send,
+{
+    type Future = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
+
+    fn foo() -> Self::Future {
+        Box::pin(async move { <T as Foo<'a>>::foo().await })
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr
new file mode 100644
index 00000000000..63e71cbc40c
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-12.no_assumptions.stderr
@@ -0,0 +1,18 @@
+error: implementation of `Robot` is not general enough
+  --> $DIR/higher-ranked-auto-trait-12.rs:31:20
+   |
+LL |       let _my_task = this_is_send(async move {
+   |  ____________________^
+LL | |         let _my_iter = IRobot {
+LL | |             id: 32,
+LL | |             robot: source,
+LL | |         };
+LL | |         yield_now().await;
+LL | |     });
+   | |______^ implementation of `Robot` is not general enough
+   |
+   = note: `Box<(dyn Robot<Id = u32> + Send + '0)>` must implement `Robot`, for any lifetime `'0`...
+   = note: ...but `Robot` is actually implemented for the type `Box<(dyn Robot<Id = u32> + Send + 'static)>`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-12.rs b/tests/ui/async-await/higher-ranked-auto-trait-12.rs
new file mode 100644
index 00000000000..b1cca5cbb00
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-12.rs
@@ -0,0 +1,40 @@
+// Repro for <https://github.com/rust-lang/rust/issues/71671#issuecomment-848994782>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+pub trait Robot {
+    type Id;
+}
+
+pub type DynRobot = Box<dyn Robot<Id = u32> + Send>;
+
+impl Robot for DynRobot {
+    type Id = u32;
+}
+
+struct IRobot<R: Robot> {
+    id: R::Id,
+    robot: R,
+}
+
+// stand-in for tokio::spawn
+fn this_is_send<T: Send>(value: T) -> T {
+    value
+}
+
+async fn yield_now() {}
+
+fn test(source: DynRobot) {
+    let _my_task = this_is_send(async move {
+        let _my_iter = IRobot {
+            id: 32,
+            robot: source,
+        };
+        yield_now().await;
+    });
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr
new file mode 100644
index 00000000000..f69218740dc
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr
@@ -0,0 +1,41 @@
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr
new file mode 100644
index 00000000000..cfbdaa8ad4b
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr
@@ -0,0 +1,60 @@
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Callable` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough
+   |
+   = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`...
+   = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Getter` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough
+   |
+   = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Callable` is not general enough
+  --> $DIR/higher-ranked-auto-trait-13.rs:65:5
+   |
+LL |     assert_send(my_send_async_method(struct_with_lifetime, data));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough
+   |
+   = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`...
+   = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.rs b/tests/ui/async-await/higher-ranked-auto-trait-13.rs
new file mode 100644
index 00000000000..4bce0f5197f
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-13.rs
@@ -0,0 +1,68 @@
+// Repro for <https://github.com/rust-lang/rust/issues/114046#issue-1819720359>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] known-bug: unknown
+//@[no_assumptions] known-bug: #110338
+
+use std::marker::PhantomData;
+
+trait Callable<'a>: Send + Sync {
+    fn callable(data: &'a [u8]);
+}
+
+trait Getter<'a>: Send + Sync {
+    type ItemSize: Send + Sync;
+
+    fn get(data: &'a [u8]);
+}
+
+struct List<'a, A: Getter<'a>> {
+    data: &'a [u8],
+    item_size: A::ItemSize, // Removing this member causes the code to compile
+    phantom: PhantomData<A>,
+}
+
+struct GetterImpl<'a, T: Callable<'a> + 'a> {
+    p: PhantomData<&'a T>,
+}
+
+impl<'a, T: Callable<'a> + 'a> Getter<'a> for GetterImpl<'a, T> {
+    type ItemSize = ();
+
+    fn get(data: &'a [u8]) {
+        <T>::callable(data);
+    }
+}
+
+struct ConstructableImpl<'a> {
+    _data: &'a [u8],
+}
+
+impl<'a> Callable<'a> for ConstructableImpl<'a> {
+    fn callable(_: &'a [u8]) {}
+}
+
+struct StructWithLifetime<'a> {
+    marker: &'a PhantomData<u8>,
+}
+
+async fn async_method() {}
+
+fn assert_send(_: impl Send + Sync) {}
+
+// This async method ought to be send, but is not
+async fn my_send_async_method(_struct_with_lifetime: &mut StructWithLifetime<'_>, data: &Vec<u8>) {
+    let _named =
+        List::<'_, GetterImpl<ConstructableImpl<'_>>> { data, item_size: (), phantom: PhantomData };
+    // Moving the await point above the constructed of _named, causes
+    // the method to become send, even though _named is Send + Sync
+    async_method().await;
+    assert_send(_named);
+}
+
+fn dummy(struct_with_lifetime: &mut StructWithLifetime<'_>, data: &Vec<u8>) {
+    assert_send(my_send_async_method(struct_with_lifetime, data));
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr
new file mode 100644
index 00000000000..b47db2b19ff
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-14.no_assumptions.stderr
@@ -0,0 +1,33 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-14.rs:20:5
+   |
+LL | /     async move {
+LL | |         let xs = unique_x.union(&cached)
+LL | |             // .copied() // works
+LL | |             .map(|x| *x) // error
+LL | |             ;
+LL | |         let blah = val.blah(xs.into_iter()).await;
+LL | |     }
+   | |_____^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 u32) -> u32` must implement `FnOnce<(&'1 u32,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&u32,)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-14.rs:20:5
+   |
+LL | /     async move {
+LL | |         let xs = unique_x.union(&cached)
+LL | |             // .copied() // works
+LL | |             .map(|x| *x) // error
+LL | |             ;
+LL | |         let blah = val.blah(xs.into_iter()).await;
+LL | |     }
+   | |_____^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 u32) -> u32` must implement `FnOnce<(&'1 u32,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&u32,)>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-14.rs b/tests/ui/async-await/higher-ranked-auto-trait-14.rs
new file mode 100644
index 00000000000..5ed12cd6e38
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-14.rs
@@ -0,0 +1,29 @@
+// Repro for <https://github.com/rust-lang/rust/issues/124757#issue-2279603232>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::collections::HashSet;
+use std::future::Future;
+
+trait MyTrait {
+    fn blah(&self, x: impl Iterator<Item = u32>) -> impl Future<Output = ()> + Send;
+}
+
+fn foo<T: MyTrait + Send + Sync>(
+    val: T,
+    unique_x: HashSet<u32>,
+) -> impl Future<Output = ()> + Send {
+    let cached = HashSet::new();
+    async move {
+        let xs = unique_x.union(&cached)
+            // .copied() // works
+            .map(|x| *x) // error
+            ;
+        let blah = val.blah(xs.into_iter()).await;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr
new file mode 100644
index 00000000000..b4f3570d9f2
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr
@@ -0,0 +1,21 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-15.rs:20:5
+   |
+LL |     require_send(future);
+   |     ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 Vec<i32>) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec<i32>,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&Vec<i32>,)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-15.rs:20:5
+   |
+LL |     require_send(future);
+   |     ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 Vec<i32>) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec<i32>,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&Vec<i32>,)>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.rs b/tests/ui/async-await/higher-ranked-auto-trait-15.rs
new file mode 100644
index 00000000000..153fcac4c3a
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-15.rs
@@ -0,0 +1,21 @@
+// Repro for <https://github.com/rust-lang/rust/issues/126044#issuecomment-2154313449>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+async fn listen() {
+    let things: Vec<Vec<i32>> = vec![];
+    for _ in things.iter().map(|n| n.iter()).flatten() {
+        // comment this line and everything compiles
+        async {}.await;
+    }
+}
+
+fn require_send<T: Send>(_x: T) {}
+
+fn main() {
+    let future = listen();
+    require_send(future);
+}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr
new file mode 100644
index 00000000000..412c31b1bd8
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-16.assumptions.stderr
@@ -0,0 +1,25 @@
+error: implementation of `AsyncFnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-16.rs:18:5
+   |
+LL | /     assert_send(async {
+LL | |         commit_if_ok(&mut ctxt, async |_| todo!()).await;
+LL | |     });
+   | |______^ implementation of `AsyncFnOnce` is not general enough
+   |
+   = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>`
+
+error: implementation of `AsyncFnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-16.rs:18:5
+   |
+LL | /     assert_send(async {
+LL | |         commit_if_ok(&mut ctxt, async |_| todo!()).await;
+LL | |     });
+   | |______^ implementation of `AsyncFnOnce` is not general enough
+   |
+   = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr
new file mode 100644
index 00000000000..412c31b1bd8
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-16.no_assumptions.stderr
@@ -0,0 +1,25 @@
+error: implementation of `AsyncFnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-16.rs:18:5
+   |
+LL | /     assert_send(async {
+LL | |         commit_if_ok(&mut ctxt, async |_| todo!()).await;
+LL | |     });
+   | |______^ implementation of `AsyncFnOnce` is not general enough
+   |
+   = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>`
+
+error: implementation of `AsyncFnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-16.rs:18:5
+   |
+LL | /     assert_send(async {
+LL | |         commit_if_ok(&mut ctxt, async |_| todo!()).await;
+LL | |     });
+   | |______^ implementation of `AsyncFnOnce` is not general enough
+   |
+   = note: `{async closure@$DIR/higher-ranked-auto-trait-16.rs:19:33: 19:42}` must implement `AsyncFnOnce<(&mut Ctxt<'1>,)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `AsyncFnOnce<(&mut Ctxt<'_>,)>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-16.rs b/tests/ui/async-await/higher-ranked-auto-trait-16.rs
new file mode 100644
index 00000000000..2b206f0a4c5
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-16.rs
@@ -0,0 +1,23 @@
+// Repro for <https://github.com/rust-lang/rust/issues/126350#issue-2349492101>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] known-bug: unknown
+//@[no_assumptions] known-bug: #110338
+
+fn assert_send<T: Send>(_: T) {}
+
+#[derive(Clone)]
+struct Ctxt<'a>(&'a ());
+
+async fn commit_if_ok<'a>(ctxt: &mut Ctxt<'a>, f: impl AsyncFnOnce(&mut Ctxt<'a>)) {
+    f(&mut ctxt.clone()).await;
+}
+
+fn operation(mut ctxt: Ctxt<'_>) {
+    assert_send(async {
+        commit_if_ok(&mut ctxt, async |_| todo!()).await;
+    });
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr
new file mode 100644
index 00000000000..152900ca1ae
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr
@@ -0,0 +1,29 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-17.rs:12:5
+   |
+LL | /     async move {
+LL | |         let iter = Adaptor::new(a.iter().map(|_: &()| {}));
+LL | |         std::future::pending::<()>().await;
+LL | |         drop(iter);
+LL | |     }
+   | |_____^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 ())` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/higher-ranked-auto-trait-17.rs:12:5
+   |
+LL | /     async move {
+LL | |         let iter = Adaptor::new(a.iter().map(|_: &()| {}));
+LL | |         std::future::pending::<()>().await;
+LL | |         drop(iter);
+LL | |     }
+   | |_____^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 ())` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-17.rs b/tests/ui/async-await/higher-ranked-auto-trait-17.rs
new file mode 100644
index 00000000000..152432466c0
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-17.rs
@@ -0,0 +1,30 @@
+// Repro for <https://github.com/rust-lang/rust/issues/114177#issue-1826550174>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+// Using `impl Future` instead of `async to ensure that the Future is Send.
+//
+// In the original code `a` would be `&[T]`. For more minimization I've removed the reference.
+fn foo(a: [(); 0]) -> impl std::future::Future<Output = ()> + Send {
+    async move {
+        let iter = Adaptor::new(a.iter().map(|_: &()| {}));
+        std::future::pending::<()>().await;
+        drop(iter);
+    }
+}
+
+struct Adaptor<T: Iterator> {
+    iter: T,
+    v: T::Item,
+}
+
+impl<T: Iterator> Adaptor<T> {
+    pub fn new(_: T) -> Self {
+        Self { iter: todo!(), v: todo!() }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr
new file mode 100644
index 00000000000..2fc44412b9d
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-2.no_assumptions.stderr
@@ -0,0 +1,49 @@
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-auto-trait-2.rs:16:9
+   |
+LL | /         async move {
+LL | |             // asks for an unspecified lifetime to outlive itself? weird diagnostics
+LL | |             self.run(t).await;
+LL | |         }
+   | |_________^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-auto-trait-2.rs:16:9
+   |
+LL | /         async move {
+LL | |             // asks for an unspecified lifetime to outlive itself? weird diagnostics
+LL | |             self.run(t).await;
+LL | |         }
+   | |_________^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-auto-trait-2.rs:16:9
+   |
+LL | /         async move {
+LL | |             // asks for an unspecified lifetime to outlive itself? weird diagnostics
+LL | |             self.run(t).await;
+LL | |         }
+   | |_________^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-auto-trait-2.rs:16:9
+   |
+LL | /         async move {
+LL | |             // asks for an unspecified lifetime to outlive itself? weird diagnostics
+LL | |             self.run(t).await;
+LL | |         }
+   | |_________^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-2.rs b/tests/ui/async-await/higher-ranked-auto-trait-2.rs
new file mode 100644
index 00000000000..6c75597265b
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-2.rs
@@ -0,0 +1,23 @@
+// Repro for <https://github.com/rust-lang/rust/issues/111105#issue-1692860759>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::future::Future;
+
+pub trait Foo: Sync {
+    fn run<'a, 'b: 'a, T: Sync>(&'a self, _: &'b T) -> impl Future<Output = ()> + 'a + Send;
+}
+
+pub trait FooExt: Foo {
+    fn run_via<'a, 'b: 'a, T: Sync>(&'a self, t: &'b T) -> impl Future<Output = ()> + 'a + Send {
+        async move {
+            // asks for an unspecified lifetime to outlive itself? weird diagnostics
+            self.run(t).await;
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr
new file mode 100644
index 00000000000..c5c98ac807e
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-3.no_assumptions.stderr
@@ -0,0 +1,12 @@
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-auto-trait-3.rs:66:9
+   |
+LL | /         async {
+LL | |             self.fi_2.get_iter(cx).await;
+LL | |         }
+   | |_________^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-3.rs b/tests/ui/async-await/higher-ranked-auto-trait-3.rs
new file mode 100644
index 00000000000..d42d4236680
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-3.rs
@@ -0,0 +1,72 @@
+// Repro for <https://github.com/rust-lang/rust/issues/100013#issue-1323807923>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+#![feature(impl_trait_in_assoc_type)]
+
+use std::future::Future;
+
+pub trait FutureIterator: 'static {
+    type Iterator;
+
+    type Future<'s, 'cx>: Future<Output = Self::Iterator> + Send + 'cx
+    where
+        's: 'cx;
+
+    fn get_iter<'s, 'cx>(&'s self, info: &'cx ()) -> Self::Future<'s, 'cx>;
+}
+
+trait IterCaller: 'static {
+    type Future1<'cx>: Future<Output = ()> + Send + 'cx;
+    type Future2<'cx>: Future<Output = ()> + Send + 'cx;
+
+    fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx>
+    where
+        's: 'cx;
+    fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx>
+    where
+        's: 'cx;
+}
+
+struct UseIter<FI1, FI2> {
+    fi_1: FI1,
+    fi_2: FI2,
+}
+
+impl<FI1, FI2> IterCaller for UseIter<FI1, FI2>
+where
+    FI1: FutureIterator + 'static + Send + Sync,
+    for<'s, 'cx> FI1::Future<'s, 'cx>: Send,
+    FI2: FutureIterator + 'static + Send + Sync,
+{
+    type Future1<'cx> = impl Future<Output = ()> + Send + 'cx
+    where
+        Self: 'cx;
+
+    type Future2<'cx> = impl Future<Output = ()> + Send + 'cx
+    where
+        Self: 'cx;
+
+    fn call_1<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future1<'cx>
+    where
+        's: 'cx,
+    {
+        async {
+            self.fi_1.get_iter(cx).await;
+        }
+    }
+
+    fn call_2<'s, 'cx>(&'s self, cx: &'cx ()) -> Self::Future2<'cx>
+    where
+        's: 'cx,
+    {
+        async {
+            self.fi_2.get_iter(cx).await;
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr
new file mode 100644
index 00000000000..5aa5b83655a
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-4.no_assumptions.stderr
@@ -0,0 +1,10 @@
+error: higher-ranked lifetime error
+  --> $DIR/higher-ranked-auto-trait-4.rs:29:5
+   |
+LL | /     async {
+LL | |         let _ = evil_function::<dyn BoringTrait, _>().await;
+LL | |     }
+   | |_____^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-4.rs b/tests/ui/async-await/higher-ranked-auto-trait-4.rs
new file mode 100644
index 00000000000..0586af41e9e
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-4.rs
@@ -0,0 +1,34 @@
+// Repro for <https://github.com/rust-lang/rust/issues/102211#issuecomment-2891975128>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::future::Future;
+
+trait BoringTrait {}
+
+trait TraitWithAssocType<I> {
+    type Assoc;
+}
+
+impl<T> TraitWithAssocType<()> for T
+where
+    T: ?Sized + 'static,
+{
+    type Assoc = ();
+}
+
+fn evil_function<T: TraitWithAssocType<I> + ?Sized, I>()
+-> impl Future<Output = Result<(), T::Assoc>> {
+    async { Ok(()) }
+}
+
+fn fails_to_compile() -> impl std::future::Future<Output = ()> + Send {
+    async {
+        let _ = evil_function::<dyn BoringTrait, _>().await;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr
new file mode 100644
index 00000000000..8fa3c7483c8
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr
@@ -0,0 +1,13 @@
+error: implementation of `Send` is not general enough
+  --> $DIR/higher-ranked-auto-trait-5.rs:13:5
+   |
+LL | /     assert_send(async {
+LL | |         call_me.call().await;
+LL | |     });
+   | |______^ implementation of `Send` is not general enough
+   |
+   = note: `Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`...
+   = note: ...but `Send` is actually implemented for the type `&'1 str`, for some specific lifetime `'1`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-5.rs b/tests/ui/async-await/higher-ranked-auto-trait-5.rs
new file mode 100644
index 00000000000..9a8b3f4357c
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-5.rs
@@ -0,0 +1,54 @@
+// Repro for <https://github.com/rust-lang/rust/issues/130113#issue-2512517191>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::future::Future;
+
+fn main() {
+    let call_me = Wrap(CallMeImpl { value: "test" });
+
+    assert_send(async {
+        call_me.call().await;
+    });
+}
+
+pub fn assert_send<F>(_future: F)
+where
+    F: Future + Send,
+{
+}
+
+pub trait CallMe {
+    fn call(&self) -> impl Future<Output = ()> + Send;
+}
+
+struct Wrap<T>(T);
+
+impl<S> CallMe for Wrap<S>
+where
+    S: CallMe + Send,
+{
+    // adding `+ Send` to this RPIT fixes the issue
+    fn call(&self) -> impl Future<Output = ()> {
+        self.0.call()
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct CallMeImpl<T> {
+    value: T,
+}
+
+impl<T> CallMe for CallMeImpl<T>
+where
+    // Can replace `Send` by `ToString`, `Clone`, whatever. When removing the
+    // `Send` bound, the compiler produces a higher-ranked lifetime error.
+    T: Send + 'static,
+{
+    fn call(&self) -> impl Future<Output = ()> {
+        async {}
+    }
+}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr
new file mode 100644
index 00000000000..d1f2d9a0753
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr
@@ -0,0 +1,50 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-auto-trait-6.rs:16:5
+   |
+LL |     Box::new(async { new(|| async { f().await }).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+              found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+   = note: no two async blocks, even if identical, have the same type
+   = help: consider pinning your async block and casting it to a trait object
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-auto-trait-6.rs:16:5
+   |
+LL |     Box::new(async { new(|| async { f().await }).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+              found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+   = note: no two async blocks, even if identical, have the same type
+   = help: consider pinning your async block and casting it to a trait object
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-auto-trait-6.rs:16:5
+   |
+LL |     Box::new(async { new(|| async { f().await }).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+              found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+   = note: no two async blocks, even if identical, have the same type
+   = help: consider pinning your async block and casting it to a trait object
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-auto-trait-6.rs:16:5
+   |
+LL |     Box::new(async { new(|| async { f().await }).await })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+              found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}`
+   = note: no two async blocks, even if identical, have the same type
+   = help: consider pinning your async block and casting it to a trait object
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.rs b/tests/ui/async-await/higher-ranked-auto-trait-6.rs
new file mode 100644
index 00000000000..2c6adf8938d
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-6.rs
@@ -0,0 +1,59 @@
+// Repro for <https://github.com/rust-lang/rust/issues/82921#issue-825114180>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use core::future::Future;
+use core::marker::PhantomData;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+async fn f() {}
+
+pub fn fail<'a>() -> Box<dyn Future<Output = ()> + Send + 'a> {
+    Box::new(async { new(|| async { f().await }).await })
+}
+
+fn new<A, B>(_a: A) -> F<A, B>
+where
+    A: Fn() -> B,
+{
+    F { _i: PhantomData }
+}
+
+trait Stream {
+    type Item;
+}
+
+struct T<A, B> {
+    _a: PhantomData<A>,
+    _b: PhantomData<B>,
+}
+
+impl<A, B> Stream for T<A, B>
+where
+    A: Fn() -> B,
+{
+    type Item = B;
+}
+
+struct F<A, B>
+where
+    A: Fn() -> B,
+{
+    _i: PhantomData<<T<A, B> as Stream>::Item>,
+}
+
+impl<A, B> Future for F<A, B>
+where
+    A: Fn() -> B,
+{
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr
new file mode 100644
index 00000000000..dcb8075566e
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-7.no_assumptions.stderr
@@ -0,0 +1,8 @@
+error: `S` does not live long enough
+  --> $DIR/higher-ranked-auto-trait-7.rs:26:5
+   |
+LL |     future::<'a, S, _>(async move {
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-7.rs b/tests/ui/async-await/higher-ranked-auto-trait-7.rs
new file mode 100644
index 00000000000..abded5a88d3
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-7.rs
@@ -0,0 +1,33 @@
+// Repro for <https://github.com/rust-lang/rust/issues/90696#issuecomment-963375847>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+#![allow(dropping_copy_types)]
+
+use std::{future::Future, marker::PhantomData};
+
+trait Trait {
+    type Associated<'a>: Send
+    where
+        Self: 'a;
+}
+
+fn future<'a, S: Trait + 'a, F>(f: F) -> F
+where
+    F: Future<Output = ()> + Send,
+{
+    f
+}
+
+fn foo<'a, S: Trait + 'a>() {
+    future::<'a, S, _>(async move {
+        let result: PhantomData<S::Associated<'a>> = PhantomData;
+        async {}.await;
+        drop(result);
+    });
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr
new file mode 100644
index 00000000000..6208675117b
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-8.no_assumptions.stderr
@@ -0,0 +1,10 @@
+error: higher-ranked lifetime error
+  --> $DIR/higher-ranked-auto-trait-8.rs:26:5
+   |
+LL |     needs_send(use_my_struct(second_struct)); // ERROR
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: could not prove `impl Future<Output = ()>: Send`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-8.rs b/tests/ui/async-await/higher-ranked-auto-trait-8.rs
new file mode 100644
index 00000000000..91cef204e44
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-8.rs
@@ -0,0 +1,27 @@
+// Repro for <https://github.com/rust-lang/rust/issues/64552#issuecomment-532801232>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+fn needs_send<T: Send>(_val: T) {}
+async fn use_async<T>(_val: T) {}
+
+struct MyStruct<'a, T: 'a> {
+    val: &'a T,
+}
+
+unsafe impl<'a, T: 'a> Send for MyStruct<'a, T> {}
+
+async fn use_my_struct(val: MyStruct<'static, &'static u8>) {
+    use_async(val).await;
+}
+
+fn main() {
+    let first_struct: MyStruct<'static, &'static u8> = MyStruct { val: &&26 };
+    let second_struct: MyStruct<'static, &'static u8> = MyStruct { val: &&27 };
+
+    needs_send(first_struct);
+    needs_send(use_my_struct(second_struct)); // ERROR
+}
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr
new file mode 100644
index 00000000000..809cbcf0cad
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-9.no_assumptions.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Debug` is not general enough
+  --> $DIR/higher-ranked-auto-trait-9.rs:43:50
+   |
+LL |     let fut: &(dyn Future<Output = ()> + Send) = &fut as _;
+   |                                                  ^^^^^^^^^ implementation of `Debug` is not general enough
+   |
+   = note: `(dyn Any + '0)` must implement `Debug`, for any lifetime `'0`...
+   = note: ...but `Debug` is actually implemented for the type `(dyn Any + 'static)`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/higher-ranked-auto-trait-9.rs b/tests/ui/async-await/higher-ranked-auto-trait-9.rs
new file mode 100644
index 00000000000..66edbf23f2b
--- /dev/null
+++ b/tests/ui/async-await/higher-ranked-auto-trait-9.rs
@@ -0,0 +1,44 @@
+// Repro for <https://github.com/rust-lang/rust/issues/87425#issue-952059416>.
+//@ edition: 2021
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::any::Any;
+use std::fmt;
+use std::future::Future;
+
+pub trait Foo {
+    type Item;
+}
+
+impl<F, I> Foo for F
+where
+    Self: FnOnce() -> I,
+    I: fmt::Debug,
+{
+    type Item = I;
+}
+
+async fn foo_item<F: Foo>(_: F) -> F::Item {
+    unimplemented!()
+}
+
+fn main() {
+    let fut = async {
+        let callback = || -> Box<dyn Any> { unimplemented!() };
+
+        // Using plain fn instead of a closure fixes the error,
+        // though you obviously can't capture any state...
+        // fn callback() -> Box<dyn Any> {
+        //     todo!()
+        // }
+
+        foo_item(callback).await;
+    };
+
+    // Removing `+ Send` bound also fixes the error,
+    // though at the cost of loosing `Send`ability...
+    let fut: &(dyn Future<Output = ()> + Send) = &fut as _;
+}
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr
index d6c3bd12aee..bb436364924 100644
--- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr
@@ -1,5 +1,5 @@
 error: implementation of `Send` is not general enough
-  --> $DIR/issue-110963-early.rs:14:5
+  --> $DIR/issue-110963-early.rs:17:5
    |
 LL | /     spawn(async move {
 LL | |         let mut hc = hc;
@@ -13,7 +13,7 @@ LL | |     });
    = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>(..) }`, for some specific lifetime `'2`
 
 error: implementation of `Send` is not general enough
-  --> $DIR/issue-110963-early.rs:14:5
+  --> $DIR/issue-110963-early.rs:17:5
    |
 LL | /     spawn(async move {
 LL | |         let mut hc = hc;
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
index 46b8fbf6f86..8c3180c0119 100644
--- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
@@ -1,5 +1,8 @@
 //@ edition: 2021
-//@ known-bug: #110963
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
 
 #![feature(return_type_notation)]
 
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 56f2be353e7..0d0c338d302 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -37,19 +37,6 @@ error: malformed `crate_name` attribute input
 LL | #[crate_name]
    | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
 
-error: malformed `coverage` attribute input
-  --> $DIR/malformed-attrs.rs:90:1
-   |
-LL | #[coverage]
-   | ^^^^^^^^^^^
-   |
-help: the following are the possible correct uses
-   |
-LL | #[coverage(off)]
-   |           +++++
-LL | #[coverage(on)]
-   |           ++++
-
 error: malformed `no_sanitize` attribute input
   --> $DIR/malformed-attrs.rs:92:1
    |
@@ -460,6 +447,19 @@ error[E0539]: malformed `link_section` attribute input
 LL | #[link_section]
    | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
 
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/malformed-attrs.rs:90:1
+   |
+LL | #[coverage]
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[coverage(off)]
+   |           +++++
+LL | #[coverage(on)]
+   |           ++++
+
 error[E0565]: malformed `no_implicit_prelude` attribute input
   --> $DIR/malformed-attrs.rs:97:1
    |
diff --git a/tests/ui/attributes/positions/used.stderr b/tests/ui/attributes/positions/used.stderr
index 96dd43a3a93..64460c178cb 100644
--- a/tests/ui/attributes/positions/used.stderr
+++ b/tests/ui/attributes/positions/used.stderr
@@ -28,7 +28,7 @@ error: attribute must be applied to a `static` variable
 LL | #[used]
    | ^^^^^^^
 LL | impl Bar for Foo {}
-   | ------------------- but this is a implementation block
+   | ------------------- but this is a trait implementation block
 
 error: attribute must be applied to a `static` variable
   --> $DIR/used.rs:21:5
diff --git a/tests/ui/cast/cast-char.rs b/tests/ui/cast/cast-char.rs
index 9634ed56f7b..5bf05072253 100644
--- a/tests/ui/cast/cast-char.rs
+++ b/tests/ui/cast/cast-char.rs
@@ -1,10 +1,58 @@
 #![deny(overflowing_literals)]
 
 fn main() {
-    const XYZ: char = 0x1F888 as char;
+    // Valid cases - should suggest char literal
+
+    // u8 range (0-255)
+    const VALID_U8_1: char = 0x41 as char; // 'A'
+    const VALID_U8_2: char = 0xFF as char; // maximum u8
+    const VALID_U8_3: char = 0x00 as char; // minimum u8
+
+    // Valid Unicode in lower range [0x0, 0xD7FF]
+    const VALID_LOW_1: char = 0x1000 as char; // 4096
+    //~^ ERROR: only `u8` can be cast into `char`
+    const VALID_LOW_2: char = 0xD7FF as char; // last valid in lower range
+    //~^ ERROR: only `u8` can be cast into `char`
+    const VALID_LOW_3: char = 0x0500 as char; // cyrillic range
+    //~^ ERROR: only `u8` can be cast into `char`
+
+    // Valid Unicode in upper range [0xE000, 0x10FFFF]
+    const VALID_HIGH_1: char = 0xE000 as char; // first valid in upper range
+    //~^ ERROR only `u8` can be cast into `char`
+    const VALID_HIGH_2: char = 0x1F888 as char; // 129160 - example from issue
+    //~^ ERROR only `u8` can be cast into `char`
+    const VALID_HIGH_3: char = 0x10FFFF as char; // maximum valid Unicode
+    //~^ ERROR only `u8` can be cast into `char`
+    const VALID_HIGH_4: char = 0xFFFD as char; // replacement character
+    //~^ ERROR only `u8` can be cast into `char`
+    const VALID_HIGH_5: char = 0x1F600 as char; // emoji
+    //~^ ERROR only `u8` can be cast into `char`
+
+    // Invalid cases - should show InvalidCharCast
+
+    // Surrogate range [0xD800, 0xDFFF] - reserved for UTF-16
+    const INVALID_SURROGATE_1: char = 0xD800 as char; // first surrogate
+    //~^ ERROR: surrogate values are not valid
+    const INVALID_SURROGATE_2: char = 0xDFFF as char; // last surrogate
+    //~^ ERROR: surrogate values are not valid
+    const INVALID_SURROGATE_3: char = 0xDB00 as char; // middle of surrogate range
+    //~^ ERROR: surrogate values are not valid
+
+    // Too large values (> 0x10FFFF)
+    const INVALID_TOO_BIG_1: char = 0x110000 as char; // one more than maximum
+    //~^ ERROR: value exceeds maximum `char` value
+    const INVALID_TOO_BIG_2: char = 0xEF8888 as char; // example from issue
+    //~^ ERROR: value exceeds maximum `char` value
+    const INVALID_TOO_BIG_3: char = 0x1FFFFF as char; // much larger
+    //~^ ERROR: value exceeds maximum `char` value
+    const INVALID_TOO_BIG_4: char = 0xFFFFFF as char; // 24-bit maximum
+    //~^ ERROR: value exceeds maximum `char` value
+
+    // Boundary cases
+    const BOUNDARY_1: char = 0xD7FE as char; // valid, before surrogate
+    //~^ ERROR only `u8` can be cast into `char`
+    const BOUNDARY_2: char = 0xE001 as char; // valid, after surrogate
     //~^ ERROR only `u8` can be cast into `char`
-    const XY: char = 129160 as char;
+    const BOUNDARY_3: char = 0x10FFFE as char; // valid, near maximum
     //~^ ERROR only `u8` can be cast into `char`
-    const ZYX: char = '\u{01F888}';
-    println!("{}", XYZ);
 }
diff --git a/tests/ui/cast/cast-char.stderr b/tests/ui/cast/cast-char.stderr
index 211937c9d6f..a8d0b3b04b0 100644
--- a/tests/ui/cast/cast-char.stderr
+++ b/tests/ui/cast/cast-char.stderr
@@ -1,8 +1,8 @@
 error: only `u8` can be cast into `char`
-  --> $DIR/cast-char.rs:4:23
+  --> $DIR/cast-char.rs:12:31
    |
-LL |     const XYZ: char = 0x1F888 as char;
-   |                       ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
+LL |     const VALID_LOW_1: char = 0x1000 as char; // 4096
+   |                               ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1000}'`
    |
 note: the lint level is defined here
   --> $DIR/cast-char.rs:1:9
@@ -11,10 +11,120 @@ LL | #![deny(overflowing_literals)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: only `u8` can be cast into `char`
-  --> $DIR/cast-char.rs:6:22
+  --> $DIR/cast-char.rs:14:31
    |
-LL |     const XY: char = 129160 as char;
-   |                      ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
+LL |     const VALID_LOW_2: char = 0xD7FF as char; // last valid in lower range
+   |                               ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{D7FF}'`
 
-error: aborting due to 2 previous errors
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:16:31
+   |
+LL |     const VALID_LOW_3: char = 0x0500 as char; // cyrillic range
+   |                               ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{500}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:20:32
+   |
+LL |     const VALID_HIGH_1: char = 0xE000 as char; // first valid in upper range
+   |                                ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{E000}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:22:32
+   |
+LL |     const VALID_HIGH_2: char = 0x1F888 as char; // 129160 - example from issue
+   |                                ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:24:32
+   |
+LL |     const VALID_HIGH_3: char = 0x10FFFF as char; // maximum valid Unicode
+   |                                ^^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{10FFFF}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:26:32
+   |
+LL |     const VALID_HIGH_4: char = 0xFFFD as char; // replacement character
+   |                                ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{FFFD}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:28:32
+   |
+LL |     const VALID_HIGH_5: char = 0x1F600 as char; // emoji
+   |                                ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F600}'`
+
+error: surrogate values are not valid for `char`
+  --> $DIR/cast-char.rs:34:39
+   |
+LL |     const INVALID_SURROGATE_1: char = 0xD800 as char; // first surrogate
+   |                                       ^^^^^^^^^^^^^^
+   |
+   = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values
+
+error: surrogate values are not valid for `char`
+  --> $DIR/cast-char.rs:36:39
+   |
+LL |     const INVALID_SURROGATE_2: char = 0xDFFF as char; // last surrogate
+   |                                       ^^^^^^^^^^^^^^
+   |
+   = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values
+
+error: surrogate values are not valid for `char`
+  --> $DIR/cast-char.rs:38:39
+   |
+LL |     const INVALID_SURROGATE_3: char = 0xDB00 as char; // middle of surrogate range
+   |                                       ^^^^^^^^^^^^^^
+   |
+   = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values
+
+error: value exceeds maximum `char` value
+  --> $DIR/cast-char.rs:42:37
+   |
+LL |     const INVALID_TOO_BIG_1: char = 0x110000 as char; // one more than maximum
+   |                                     ^^^^^^^^^^^^^^^^
+   |
+   = note: maximum valid `char` value is `0x10FFFF`
+
+error: value exceeds maximum `char` value
+  --> $DIR/cast-char.rs:44:37
+   |
+LL |     const INVALID_TOO_BIG_2: char = 0xEF8888 as char; // example from issue
+   |                                     ^^^^^^^^^^^^^^^^
+   |
+   = note: maximum valid `char` value is `0x10FFFF`
+
+error: value exceeds maximum `char` value
+  --> $DIR/cast-char.rs:46:37
+   |
+LL |     const INVALID_TOO_BIG_3: char = 0x1FFFFF as char; // much larger
+   |                                     ^^^^^^^^^^^^^^^^
+   |
+   = note: maximum valid `char` value is `0x10FFFF`
+
+error: value exceeds maximum `char` value
+  --> $DIR/cast-char.rs:48:37
+   |
+LL |     const INVALID_TOO_BIG_4: char = 0xFFFFFF as char; // 24-bit maximum
+   |                                     ^^^^^^^^^^^^^^^^
+   |
+   = note: maximum valid `char` value is `0x10FFFF`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:52:30
+   |
+LL |     const BOUNDARY_1: char = 0xD7FE as char; // valid, before surrogate
+   |                              ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{D7FE}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:54:30
+   |
+LL |     const BOUNDARY_2: char = 0xE001 as char; // valid, after surrogate
+   |                              ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{E001}'`
+
+error: only `u8` can be cast into `char`
+  --> $DIR/cast-char.rs:56:30
+   |
+LL |     const BOUNDARY_3: char = 0x10FFFE as char; // valid, near maximum
+   |                              ^^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{10FFFE}'`
+
+error: aborting due to 18 previous errors
 
diff --git a/tests/ui/cfg/crt-static-with-target-features-works.rs b/tests/ui/cfg/crt-static-with-target-features-works.rs
new file mode 100644
index 00000000000..bce02229624
--- /dev/null
+++ b/tests/ui/cfg/crt-static-with-target-features-works.rs
@@ -0,0 +1,24 @@
+// Test to ensure that specifying a value for crt-static in target features
+// does not result in skipping the features following it.
+// This is a regression test for #144143
+
+//@ add-core-stubs
+//@ needs-llvm-components: x86
+//@ compile-flags: --target=x86_64-unknown-linux-gnu
+//@ compile-flags: -Ctarget-feature=+crt-static,+avx2
+
+#![crate_type = "rlib"]
+#![feature(no_core, rustc_attrs, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[rustc_builtin_macro]
+macro_rules! compile_error {
+    () => {};
+}
+
+#[cfg(target_feature = "avx2")]
+compile_error!("+avx2");
+//~^ ERROR: +avx2
diff --git a/tests/ui/cfg/crt-static-with-target-features-works.stderr b/tests/ui/cfg/crt-static-with-target-features-works.stderr
new file mode 100644
index 00000000000..6f265c685bb
--- /dev/null
+++ b/tests/ui/cfg/crt-static-with-target-features-works.stderr
@@ -0,0 +1,8 @@
+error: +avx2
+  --> $DIR/crt-static-with-target-features-works.rs:23:1
+   |
+LL | compile_error!("+avx2");
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/check-cfg/cfg-crate-features.rs b/tests/ui/check-cfg/cfg-crate-features.rs
new file mode 100644
index 00000000000..16be8aaeeaa
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-crate-features.rs
@@ -0,0 +1,13 @@
+// https://github.com/rust-lang/rust/issues/143977
+// Check that features are available when an attribute is applied to a crate
+
+#![cfg(version("1.0"))]
+//~^ ERROR `cfg(version)` is experimental and subject to change
+
+// Using invalid value `does_not_exist`,
+// so we don't accidentally configure out the crate for any certain OS
+#![cfg(not(target(os = "does_not_exist")))]
+//~^ ERROR compact `cfg(target(..))` is experimental and subject to change
+//~| WARN unexpected `cfg` condition value: `does_not_exist`
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr
new file mode 100644
index 00000000000..60a5404c073
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-crate-features.stderr
@@ -0,0 +1,33 @@
+error[E0658]: `cfg(version)` is experimental and subject to change
+  --> $DIR/cfg-crate-features.rs:4:8
+   |
+LL | #![cfg(version("1.0"))]
+   |        ^^^^^^^^^^^^^^
+   |
+   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
+   = help: add `#![feature(cfg_version)]` 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]: compact `cfg(target(..))` is experimental and subject to change
+  --> $DIR/cfg-crate-features.rs:9:12
+   |
+LL | #![cfg(not(target(os = "does_not_exist")))]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information
+   = help: add `#![feature(cfg_target_compact)]` 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: unexpected `cfg` condition value: `does_not_exist`
+  --> $DIR/cfg-crate-features.rs:9:19
+   |
+LL | #![cfg(not(target(os = "does_not_exist")))]
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, and `uefi` and 9 more
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
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/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
index f68fdb3b651..32fa46b92b3 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
@@ -1,14 +1,15 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/issue-71348.rs:18:40
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
-   |                                        ^^           -- ------------------------ the lifetimes get resolved as `'a`
+   |                                        ^^           -- ------------------------ the same lifetime is hidden here
    |                                        |            |
-   |                                        |            the lifetimes get resolved as `'a`
-   |                                        this lifetime flows to the output
+   |                                        |            the same lifetime is named here
+   |                                        the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<'a, N>>::Target
    |                                                                     +++
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs
index c6563c80305..9053f362ce4 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.rs
+++ b/tests/ui/const-generics/type-dependent/issue-71348.rs
@@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> {
 impl Foo {
     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
     //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
-    //[full]~^^ WARNING lifetime flowing from input to output with different syntax
+    //[full]~^^ WARNING hiding a lifetime that's named elsewhere is confusing
     where
         Self: Get<'a, N>,
     {
diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs
index 0bc8585a4ee..7e3df92a2bf 100644
--- a/tests/ui/consts/const-compare-bytes-ub.rs
+++ b/tests/ui/consts/const-compare-bytes-ub.rs
@@ -1,6 +1,6 @@
 //@ check-fail
 
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, const_cmp)]
 use std::intrinsics::compare_bytes;
 use std::mem::MaybeUninit;
 
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-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs
index cd5cdfd0400..9563375555c 100644
--- a/tests/ui/consts/const-compare-bytes.rs
+++ b/tests/ui/consts/const-compare-bytes.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, const_cmp)]
 use std::intrinsics::compare_bytes;
 
 fn main() {
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/auxiliary/stability.rs b/tests/ui/consts/const-eval/auxiliary/stability.rs
index e6159551860..48ced3bc51e 100644
--- a/tests/ui/consts/const-eval/auxiliary/stability.rs
+++ b/tests/ui/consts/const-eval/auxiliary/stability.rs
@@ -1,10 +1,11 @@
 // Crate that exports a const fn. Used for testing cross-crate.
 
-#![crate_type="rlib"]
+#![crate_type = "rlib"]
 #![stable(feature = "rust1", since = "1.0.0")]
-
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo", issue = "none")]
-pub const fn foo() -> u32 { 42 }
+#[rustc_const_unstable(feature = "foo", issue = "none")]
+pub const fn foo() -> u32 {
+    42
+}
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/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs
index 83ed496ac2c..af24e463b50 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs
@@ -8,11 +8,11 @@ const FOO_RAW: *const i32 = foo();
 
 const fn foo() -> &'static i32 {
     let t = unsafe {
-        let i = intrinsics::const_allocate(4, 4) as * mut i32;
+        let i = intrinsics::const_allocate(4, 4) as *mut i32;
         *i = 20;
         i
     };
-    unsafe { &*t }
+    unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *const i32) }
 }
 fn main() {
     assert_eq!(*FOO, 20);
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
index 11ed0841a00..a8c7ee93971 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
@@ -1,7 +1,7 @@
 error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
   --> $DIR/alloc_intrinsic_uninit.rs:7:1
    |
-LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
+LL | const BAR: &i32 = unsafe {
    | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
index 691bde87d2f..47e1c22cc2c 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
@@ -1,7 +1,7 @@
 error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
   --> $DIR/alloc_intrinsic_uninit.rs:7:1
    |
-LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
+LL | const BAR: &i32 = unsafe {
    | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs
index ffc35ca1ddc..c54115de204 100644
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs
+++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs
@@ -4,6 +4,8 @@
 #![feature(const_heap)]
 use std::intrinsics;
 
-const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
-//~^ ERROR: uninitialized memory
+const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory
+    // Make the pointer immutable to avoid errors related to mutable pointers in constants.
+    &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *const i32)
+};
 fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs
deleted file mode 100644
index 26cb69e458b..00000000000
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// We unleash Miri here since this test demonstrates code that bypasses the checks against interning
-// mutable pointers, which currently ICEs. Unleashing Miri silences the ICE.
-//@ compile-flags: -Zunleash-the-miri-inside-of-you
-#![feature(core_intrinsics)]
-#![feature(const_heap)]
-use std::intrinsics;
-
-const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
-//~^ error: mutable pointer in final value of constant
-
-fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr
deleted file mode 100644
index 0dc49dc3cd8..00000000000
--- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: encountered mutable pointer in final value of constant
-  --> $DIR/alloc_intrinsic_untyped.rs:8:1
-   |
-LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs
index 3cc035c66d3..515e12d2b77 100644
--- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs
+++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs
@@ -12,7 +12,7 @@ const _X: () = unsafe {
 const Y: &u32 = unsafe {
     let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
     *ptr = 42;
-    &*ptr
+    &*(intrinsics::const_make_global(ptr as *mut u8) as *const u32)
 };
 
 const Z: &u32 = &42;
diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.rs b/tests/ui/consts/const-eval/heap/make-global-dangling.rs
new file mode 100644
index 00000000000..f4c5929bc41
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global-dangling.rs
@@ -0,0 +1,18 @@
+// Ensure that we can't call `const_make_global` on dangling pointers.
+
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const Y: &u32 = unsafe {
+    &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32)
+    //~^ error: pointer not dereferenceable
+};
+
+const Z: &u32 = unsafe {
+    &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32)
+    //~^ error: pointer not dereferenceable
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.stderr b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr
new file mode 100644
index 00000000000..48c2796d0bf
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr
@@ -0,0 +1,15 @@
+error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
+  --> $DIR/make-global-dangling.rs:9:8
+   |
+LL |     &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32)
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
+
+error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
+  --> $DIR/make-global-dangling.rs:14:8
+   |
+LL |     &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32)
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/heap/make-global-other.rs b/tests/ui/consts/const-eval/heap/make-global-other.rs
new file mode 100644
index 00000000000..4e2a59de13e
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global-other.rs
@@ -0,0 +1,15 @@
+// Ensure that we can't call `const_make_global` on pointers not in the current interpreter.
+
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const X: &i32 = &0;
+
+const Y: &i32 = unsafe {
+    &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32)
+    //~^ error: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm>
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/make-global-other.stderr b/tests/ui/consts/const-eval/heap/make-global-other.stderr
new file mode 100644
index 00000000000..ed0d768cf37
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global-other.stderr
@@ -0,0 +1,9 @@
+error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm>
+  --> $DIR/make-global-other.rs:11:8
+   |
+LL |     &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32)
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` 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/heap/make-global-twice.rs b/tests/ui/consts/const-eval/heap/make-global-twice.rs
new file mode 100644
index 00000000000..0cd617cea3e
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global-twice.rs
@@ -0,0 +1,18 @@
+// Ensure that we can't call `const_make_global` twice.
+
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const Y: &i32 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    let i = ptr as *mut i32;
+    *i = 20;
+    intrinsics::const_make_global(ptr);
+    intrinsics::const_make_global(ptr);
+    //~^ error: attempting to call `const_make_global` twice on the same allocation ALLOC0
+    &*i
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.stderr b/tests/ui/consts/const-eval/heap/make-global-twice.stderr
new file mode 100644
index 00000000000..95cdb9694d8
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global-twice.stderr
@@ -0,0 +1,9 @@
+error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0
+  --> $DIR/make-global-twice.rs:13:5
+   |
+LL |     intrinsics::const_make_global(ptr);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` 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/heap/make-global.rs b/tests/ui/consts/const-eval/heap/make-global.rs
new file mode 100644
index 00000000000..b26fe2434ab
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/make-global.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+use std::intrinsics;
+
+const FOO: &i32 = foo();
+const FOO_RAW: *const i32 = foo();
+
+const fn foo() -> &'static i32 {
+    unsafe {
+        let ptr = intrinsics::const_allocate(4, 4);
+        let t = ptr as *mut i32;
+        *t = 20;
+        intrinsics::const_make_global(ptr);
+        &*t
+    }
+}
+fn main() {
+    assert_eq!(*FOO, 20);
+    assert_eq!(unsafe { *FOO_RAW }, 20);
+}
diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs
new file mode 100644
index 00000000000..bea2a5949c2
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs
@@ -0,0 +1,15 @@
+// Ensure that once an allocation is "made global", we can no longer mutate it.
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+use std::intrinsics;
+
+const A: &u8 = unsafe {
+    let ptr = intrinsics::const_allocate(1, 1);
+    *ptr = 1;
+    let ptr: *const u8 = intrinsics::const_make_global(ptr);
+    *(ptr as *mut u8) = 2;
+    //~^ error: writing to ALLOC0 which is read-only
+    &*ptr
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr
new file mode 100644
index 00000000000..0e88ea77d1c
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr
@@ -0,0 +1,9 @@
+error[E0080]: writing to ALLOC0 which is read-only
+  --> $DIR/ptr_made_global_mutated.rs:10:5
+   |
+LL |     *(ptr as *mut u8) = 2;
+   |     ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` 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/heap/ptr_not_made_global.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs
new file mode 100644
index 00000000000..6980e92c218
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs
@@ -0,0 +1,24 @@
+// Ensure that we reject interning `const_allocate`d allocations in the final value of constants
+// if they have not been made global through `const_make_global`. The pointers are made *immutable*
+// to focus the test on the missing `make_global`; `ptr_not_made_global_mut.rs` covers the case
+// where the pointer remains mutable.
+
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+use std::intrinsics;
+
+const FOO: &i32 = foo();
+//~^ error: encountered `const_allocate` pointer in final value that was not made global
+const FOO_RAW: *const i32 = foo();
+//~^ error: encountered `const_allocate` pointer in final value that was not made global
+
+const fn foo() -> &'static i32 {
+    let t = unsafe {
+        let i = intrinsics::const_allocate(4, 4) as *mut i32;
+        *i = 20;
+        i
+    };
+    unsafe { &*t }
+}
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr
new file mode 100644
index 00000000000..cb2bb1e8cd8
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr
@@ -0,0 +1,18 @@
+error: encountered `const_allocate` pointer in final value that was not made global
+  --> $DIR/ptr_not_made_global.rs:10:1
+   |
+LL | const FOO: &i32 = foo();
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: use `const_make_global` to make allocated pointers immutable before returning
+
+error: encountered `const_allocate` pointer in final value that was not made global
+  --> $DIR/ptr_not_made_global.rs:12:1
+   |
+LL | const FOO_RAW: *const i32 = foo();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: use `const_make_global` to make allocated pointers immutable before returning
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs
new file mode 100644
index 00000000000..e44a3f7a23c
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs
@@ -0,0 +1,11 @@
+// Ensure that we reject interning `const_allocate`d allocations in the final value of constants
+// if they have not been made global through `const_make_global`. This covers the case where the
+// pointer is even still mutable, which used to ICE.
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+use std::intrinsics;
+
+const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
+//~^ error: encountered `const_allocate` pointer in final value that was not made global
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr
new file mode 100644
index 00000000000..2445ce633d6
--- /dev/null
+++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr
@@ -0,0 +1,10 @@
+error: encountered `const_allocate` pointer in final value that was not made global
+  --> $DIR/ptr_not_made_global_mut.rs:8:1
+   |
+LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: use `const_make_global` to make allocated pointers immutable before returning
+
+error: aborting due to 1 previous error
+
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/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
index 2372d1c3e3d..fd3ed8f1826 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
@@ -8,8 +8,8 @@ extern "C" {
 }
 
 const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
-//~^ ERROR the size for values of type `Opaque` cannot be known
+//~^ ERROR `extern type` does not have known layout
 const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
-//~^ ERROR the size for values of type `Opaque` cannot be known
+//~^ ERROR `extern type` does not have known layout
 
 fn main() {}
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
index 825b9e94158..23f7aaf538e 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
@@ -1,39 +1,15 @@
-error[E0277]: the size for values of type `Opaque` cannot be known
-  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:43
+error[E0080]: `extern type` does not have known layout
+  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31
    |
 LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
-   |                               ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque`
-   |                               |
-   |                               required by a bound introduced by this call
-   |
-   = note: the trait bound `Opaque: MetaSized` is not satisfied
-note: required by a bound in `std::intrinsics::size_of_val`
-  --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
-help: consider borrowing here
-   |
-LL | const _SIZE: usize = unsafe { size_of_val(&(&4 as *const i32 as *const Opaque)) };
-   |                                           ++                                 +
-LL | const _SIZE: usize = unsafe { size_of_val(&mut (&4 as *const i32 as *const Opaque)) };
-   |                                           ++++++                                 +
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_SIZE` failed here
 
-error[E0277]: the size for values of type `Opaque` cannot be known
-  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:45
+error[E0080]: `extern type` does not have known layout
+  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:32
    |
 LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
-   |                                ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque`
-   |                                |
-   |                                required by a bound introduced by this call
-   |
-   = note: the trait bound `Opaque: MetaSized` is not satisfied
-note: required by a bound in `std::intrinsics::align_of_val`
-  --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
-help: consider borrowing here
-   |
-LL | const _ALIGN: usize = unsafe { align_of_val(&(&4 as *const i32 as *const Opaque)) };
-   |                                             ++                                 +
-LL | const _ALIGN: usize = unsafe { align_of_val(&mut (&4 as *const i32 as *const Opaque)) };
-   |                                             ++++++                                 +
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs
index 26aa9230a39..e13fad78441 100644
--- a/tests/ui/consts/const-try.rs
+++ b/tests/ui/consts/const-try.rs
@@ -13,14 +13,14 @@ struct TryMe;
 struct Error;
 
 impl const FromResidual<Error> for TryMe {
-    //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+    //~^ ERROR const `impl` for trait `FromResidual` which is not `const`
     fn from_residual(residual: Error) -> Self {
         TryMe
     }
 }
 
 impl const Try for TryMe {
-    //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]`
+    //~^ ERROR const `impl` for trait `Try` which is not `const`
     type Output = ();
     type Residual = Error;
     fn from_output(output: Self::Output) -> Self {
diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr
index 4209ca1d526..7004ea3e6db 100644
--- a/tests/ui/consts/const-try.stderr
+++ b/tests/ui/consts/const-try.stderr
@@ -1,19 +1,19 @@
-error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+error: const `impl` for trait `FromResidual` which is not `const`
   --> $DIR/const-try.rs:15:12
    |
 LL | impl const FromResidual<Error> for TryMe {
    |            ^^^^^^^^^^^^^^^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Try` which is not `const`
   --> $DIR/const-try.rs:22:12
    |
 LL | impl const Try for TryMe {
    |            ^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0015]: `?` is not allowed on `TryMe` in constant functions
diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs
index 22a607e9e0e..0ea75f2a2f4 100644
--- a/tests/ui/consts/const_transmute_type_id4.rs
+++ b/tests/ui/consts/const_transmute_type_id4.rs
@@ -10,7 +10,7 @@ const _: () = {
         std::ptr::write(ptr.offset(0), main as fn() as *const ());
     }
     assert!(a == b);
-    //~^ ERROR: type_id_eq: `TypeId` provenance is not a type id
+    //~^ ERROR: invalid `TypeId` value
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr
index b418a79d7f0..b224227cf35 100644
--- a/tests/ui/consts/const_transmute_type_id4.stderr
+++ b/tests/ui/consts/const_transmute_type_id4.stderr
@@ -1,4 +1,4 @@
-error[E0080]: type_id_eq: `TypeId` provenance is not a type id
+error[E0080]: invalid `TypeId` value: not all bytes carry type id metadata
   --> $DIR/const_transmute_type_id4.rs:12:13
    |
 LL |     assert!(a == b);
diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs
index 0a9ba01e0dd..ae0429f8dbb 100644
--- a/tests/ui/consts/const_transmute_type_id5.rs
+++ b/tests/ui/consts/const_transmute_type_id5.rs
@@ -1,12 +1,11 @@
-//! Test that we require an equal TypeId to have the same integer
-//! part, even if the provenance matches.
+//! Test that we require an equal TypeId to have an integer part that properly
+//! reflects the type id hash.
 
 #![feature(const_type_id, const_trait_impl, const_cmp)]
 
 use std::any::TypeId;
 
 const _: () = {
-    let a = TypeId::of::<()>();
     let mut b = TypeId::of::<()>();
     unsafe {
         let ptr = &mut b as *mut TypeId as *mut *const ();
@@ -14,8 +13,8 @@ const _: () = {
         let val = std::ptr::read(ptr);
         std::ptr::write(ptr.offset(1), val);
     }
-    assert!(a == b);
-    //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
+    assert!(b == b);
+    //~^ ERROR: invalid `TypeId` value
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr
index 59823fcc1c9..6205679ebb6 100644
--- a/tests/ui/consts/const_transmute_type_id5.stderr
+++ b/tests/ui/consts/const_transmute_type_id5.stderr
@@ -1,7 +1,7 @@
-error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
-  --> $DIR/const_transmute_type_id5.rs:17:13
+error[E0080]: invalid `TypeId` value: the hash does not match the type id metadata
+  --> $DIR/const_transmute_type_id5.rs:16:13
    |
-LL |     assert!(a == b);
+LL |     assert!(b == b);
    |             ^^^^^^ evaluation of `_` failed inside this call
    |
 note: inside `<TypeId as PartialEq>::eq`
diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr
index 4b13826584d..8d10bddaa45 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.stderr
+++ b/tests/ui/consts/rustc-const-stability-require-const.stderr
@@ -23,30 +23,6 @@ LL | pub fn bar() {}
    | ^^^^^^^^^^^^
 
 error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
-  --> $DIR/rustc-const-stability-require-const.rs:21:5
-   |
-LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: make the function or method const
-  --> $DIR/rustc-const-stability-require-const.rs:21:5
-   |
-LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
-  --> $DIR/rustc-const-stability-require-const.rs:26:5
-   |
-LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: make the function or method const
-  --> $DIR/rustc-const-stability-require-const.rs:26:5
-   |
-LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
   --> $DIR/rustc-const-stability-require-const.rs:32:1
    |
 LL | pub extern "C" fn bar_c() {}
@@ -86,5 +62,29 @@ LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
 LL | pub const fn barfoo_unstable() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:21:5
+   |
+LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:21:5
+   |
+LL |     pub fn salad(&self) -> &'static str { "mmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
+  --> $DIR/rustc-const-stability-require-const.rs:26:5
+   |
+LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function or method const
+  --> $DIR/rustc-const-stability-require-const.rs:26:5
+   |
+LL |     pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr
index a3ef4031a13..55c08539688 100644
--- a/tests/ui/consts/rustc-impl-const-stability.stderr
+++ b/tests/ui/consts/rustc-impl-const-stability.stderr
@@ -1,10 +1,10 @@
-error: const `impl` for trait `Debug` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Debug` which is not `const`
   --> $DIR/rustc-impl-const-stability.rs:15:12
    |
 LL | impl const std::fmt::Debug for Data {
    |            ^^^^^^^^^^^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error: aborting due to 1 previous error
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/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs
index b07fad18aee..e528f031d52 100644
--- a/tests/ui/coroutine/clone-impl.rs
+++ b/tests/ui/coroutine/clone-impl.rs
@@ -38,39 +38,40 @@ fn test2() {
     check_clone(&gen_copy_1);
 }
 
-fn test3() {
+fn test3_upvars() {
     let clonable_0: Vec<u32> = Vec::new();
     let gen_clone_0 = #[coroutine]
     move || {
-        let v = vec!['a'];
-        yield;
-        drop(v);
         drop(clonable_0);
     };
     check_copy(&gen_clone_0);
     //~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
-    //~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
     check_clone(&gen_clone_0);
 }
 
+fn test3_witness() {
+    let gen_clone_1 = #[coroutine]
+    move || {
+        let v = vec!['a'];
+        yield;
+        drop(v);
+    };
+    check_copy(&gen_clone_1);
+    //~^ ERROR the trait bound `Vec<char>: Copy` is not satisfied
+    check_clone(&gen_clone_1);
+}
+
 fn test4() {
     let clonable_1: Vec<u32> = Vec::new();
     let gen_clone_1 = #[coroutine]
     move || {
-        let v = vec!['a'];
-        /*
-        let n = NonClone;
-        drop(n);
-        */
         yield;
         let n = NonClone;
         drop(n);
-        drop(v);
         drop(clonable_1);
     };
     check_copy(&gen_clone_1);
     //~^ ERROR the trait bound `Vec<u32>: Copy` is not satisfied
-    //~| ERROR the trait bound `Vec<char>: Copy` is not satisfied
     check_clone(&gen_clone_1);
 }
 
diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr
index ed933fe784e..714e5aa3d9e 100644
--- a/tests/ui/coroutine/clone-impl.stderr
+++ b/tests/ui/coroutine/clone-impl.stderr
@@ -1,104 +1,59 @@
 error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
-  --> $DIR/clone-impl.rs:50:5
+  --> $DIR/clone-impl.rs:47:16
    |
 LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
 ...
 LL |     check_copy(&gen_clone_0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec<u32>`
+   |                ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec<u32>`
    |
 note: captured value does not implement `Copy`
-  --> $DIR/clone-impl.rs:48:14
+  --> $DIR/clone-impl.rs:45:14
    |
 LL |         drop(clonable_0);
    |              ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
 note: required by a bound in `check_copy`
-  --> $DIR/clone-impl.rs:90:18
+  --> $DIR/clone-impl.rs:91:18
    |
 LL | fn check_copy<T: Copy>(_x: &T) {}
    |                  ^^^^ required by this bound in `check_copy`
 
-error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
-  --> $DIR/clone-impl.rs:50:5
+error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`
+  --> $DIR/clone-impl.rs:73:16
    |
 LL |     move || {
-   |     ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`
-...
-LL |     check_copy(&gen_clone_0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec<char>`
-   |
-note: coroutine does not implement `Copy` as this value is used across a yield
-  --> $DIR/clone-impl.rs:46:9
-   |
-LL |         let v = vec!['a'];
-   |             - has type `Vec<char>` which does not implement `Copy`
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `v` maybe used later
-note: required by a bound in `check_copy`
-  --> $DIR/clone-impl.rs:90:18
-   |
-LL | fn check_copy<T: Copy>(_x: &T) {}
-   |                  ^^^^ required by this bound in `check_copy`
-
-error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
-  --> $DIR/clone-impl.rs:71:5
-   |
-LL |     move || {
-   |     ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
+   |     ------- within this `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`
 ...
 LL |     check_copy(&gen_clone_1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec<u32>`
+   |                ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`, the trait `Copy` is not implemented for `Vec<u32>`
    |
 note: captured value does not implement `Copy`
-  --> $DIR/clone-impl.rs:69:14
+  --> $DIR/clone-impl.rs:71:14
    |
 LL |         drop(clonable_1);
    |              ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
 note: required by a bound in `check_copy`
-  --> $DIR/clone-impl.rs:90:18
-   |
-LL | fn check_copy<T: Copy>(_x: &T) {}
-   |                  ^^^^ required by this bound in `check_copy`
-
-error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
-  --> $DIR/clone-impl.rs:71:5
-   |
-LL |     move || {
-   |     ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`
-...
-LL |     check_copy(&gen_clone_1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec<char>`
-   |
-note: coroutine does not implement `Copy` as this value is used across a yield
-  --> $DIR/clone-impl.rs:65:9
-   |
-LL |         let v = vec!['a'];
-   |             - has type `Vec<char>` which does not implement `Copy`
-...
-LL |         yield;
-   |         ^^^^^ yield occurs here, with `v` maybe used later
-note: required by a bound in `check_copy`
-  --> $DIR/clone-impl.rs:90:18
+  --> $DIR/clone-impl.rs:91:18
    |
 LL | fn check_copy<T: Copy>(_x: &T) {}
    |                  ^^^^ required by this bound in `check_copy`
 
-error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
-  --> $DIR/clone-impl.rs:84:5
+error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`
+  --> $DIR/clone-impl.rs:85:16
    |
 LL |     move || {
-   |     ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
+   |     ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`
 ...
 LL |     check_copy(&gen_non_clone);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Copy` is not implemented for `NonClone`
+   |                ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Copy` is not implemented for `NonClone`
    |
 note: captured value does not implement `Copy`
-  --> $DIR/clone-impl.rs:82:14
+  --> $DIR/clone-impl.rs:83:14
    |
 LL |         drop(non_clonable);
    |              ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy`
 note: required by a bound in `check_copy`
-  --> $DIR/clone-impl.rs:90:18
+  --> $DIR/clone-impl.rs:91:18
    |
 LL | fn check_copy<T: Copy>(_x: &T) {}
    |                  ^^^^ required by this bound in `check_copy`
@@ -108,22 +63,22 @@ LL + #[derive(Copy)]
 LL | struct NonClone;
    |
 
-error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
-  --> $DIR/clone-impl.rs:86:5
+error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`
+  --> $DIR/clone-impl.rs:87:17
    |
 LL |     move || {
-   |     ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`
+   |     ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`
 ...
 LL |     check_clone(&gen_non_clone);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Clone` is not implemented for `NonClone`
+   |                 ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Clone` is not implemented for `NonClone`
    |
 note: captured value does not implement `Clone`
-  --> $DIR/clone-impl.rs:82:14
+  --> $DIR/clone-impl.rs:83:14
    |
 LL |         drop(non_clonable);
    |              ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone`
 note: required by a bound in `check_clone`
-  --> $DIR/clone-impl.rs:91:19
+  --> $DIR/clone-impl.rs:92:19
    |
 LL | fn check_clone<T: Clone>(_x: &T) {}
    |                   ^^^^^ required by this bound in `check_clone`
@@ -133,6 +88,28 @@ LL + #[derive(Clone)]
 LL | struct NonClone;
    |
 
-error: aborting due to 6 previous errors
+error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`
+  --> $DIR/clone-impl.rs:59:5
+   |
+LL |     move || {
+   |     ------- within this `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`
+...
+LL |     check_copy(&gen_clone_1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`, the trait `Copy` is not implemented for `Vec<char>`
+   |
+note: coroutine does not implement `Copy` as this value is used across a yield
+  --> $DIR/clone-impl.rs:56:9
+   |
+LL |         let v = vec!['a'];
+   |             - has type `Vec<char>` which does not implement `Copy`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `v` maybe used later
+note: required by a bound in `check_copy`
+  --> $DIR/clone-impl.rs:91:18
+   |
+LL | fn check_copy<T: Copy>(_x: &T) {}
+   |                  ^^^^ required by this bound in `check_copy`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr
index 2f9f20cf1ff..4a1e5b078a8 100644
--- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr
+++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr
@@ -11,7 +11,7 @@ LL | |     };
    | |_____^ expected `()`, found coroutine
    |
    = note: expected unit type `()`
-              found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness=?6t}`
+              found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness={main::{closure#0}}}`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
index dc84394fe3c..5a003af42da 100644
--- a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
+++ b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
@@ -1,10 +1,10 @@
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/bad-attr-ice.rs:11:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
@@ -13,3 +13,4 @@ LL | #[coverage(on)]
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
index 49b8974bfdf..4501e5e9dc8 100644
--- a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
+++ b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
@@ -1,26 +1,27 @@
-error: malformed `coverage` attribute input
+error[E0658]: the `#[coverage]` attribute is an experimental feature
   --> $DIR/bad-attr-ice.rs:11:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
    |
-help: the following are the possible correct uses
-   |
-LL | #[coverage(off)]
-   |           +++++
-LL | #[coverage(on)]
-   |           ++++
+   = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
+   = help: add `#![feature(coverage_attribute)]` 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]: the `#[coverage]` attribute is an experimental feature
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/bad-attr-ice.rs:11:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-   = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
-   = help: add `#![feature(coverage_attribute)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[coverage(off)]
+   |           +++++
+LL | #[coverage(on)]
+   |           ++++
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0539, E0658.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr
index fa500b54209..927f61da08d 100644
--- a/tests/ui/coverage-attr/bad-syntax.stderr
+++ b/tests/ui/coverage-attr/bad-syntax.stderr
@@ -1,23 +1,59 @@
-error: malformed `coverage` attribute input
+error: expected identifier, found `,`
+  --> $DIR/bad-syntax.rs:44:12
+   |
+LL | #[coverage(,off)]
+   |            ^ expected identifier
+   |
+help: remove this comma
+   |
+LL - #[coverage(,off)]
+LL + #[coverage(off)]
+   |
+
+error: multiple `coverage` attributes
+  --> $DIR/bad-syntax.rs:9:1
+   |
+LL | #[coverage(off)]
+   | ^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/bad-syntax.rs:10:1
+   |
+LL | #[coverage(off)]
+   | ^^^^^^^^^^^^^^^^
+
+error: multiple `coverage` attributes
+  --> $DIR/bad-syntax.rs:13:1
+   |
+LL | #[coverage(off)]
+   | ^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/bad-syntax.rs:14:1
+   |
+LL | #[coverage(on)]
+   | ^^^^^^^^^^^^^^^
+
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:17:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:20:1
    |
 LL | #[coverage = true]
-   | ^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = true]
 LL + #[coverage(off)]
@@ -26,26 +62,30 @@ LL - #[coverage = true]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0805]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:23:1
    |
 LL | #[coverage()]
-   | ^^^^^^^^^^^^^
+   | ^^^^^^^^^^--^
+   |           |
+   |           expected a single argument here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |            +++
 LL | #[coverage(on)]
    |            ++
 
-error: malformed `coverage` attribute input
+error[E0805]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:26:1
    |
 LL | #[coverage(off, off)]
-   | ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^----------^
+   |           |
+   |           expected a single argument here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(off, off)]
 LL + #[coverage(off)]
@@ -54,13 +94,15 @@ LL - #[coverage(off, off)]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0805]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:29:1
    |
 LL | #[coverage(off, on)]
-   | ^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^---------^
+   |           |
+   |           expected a single argument here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(off, on)]
 LL + #[coverage(off)]
@@ -69,13 +111,15 @@ LL - #[coverage(off, on)]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:32:1
    |
 LL | #[coverage(bogus)]
-   | ^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^-----^^
+   |            |
+   |            valid arguments are `on` or `off`
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(bogus)]
 LL + #[coverage(off)]
@@ -84,13 +128,15 @@ LL - #[coverage(bogus)]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0805]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:35:1
    |
 LL | #[coverage(bogus, off)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^------------^
+   |           |
+   |           expected a single argument here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(bogus, off)]
 LL + #[coverage(off)]
@@ -99,13 +145,15 @@ LL - #[coverage(bogus, off)]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0805]: malformed `coverage` attribute input
   --> $DIR/bad-syntax.rs:38:1
    |
 LL | #[coverage(off, bogus)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^------------^
+   |           |
+   |           expected a single argument here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(off, bogus)]
 LL + #[coverage(off)]
@@ -114,41 +162,7 @@ LL - #[coverage(off, bogus)]
 LL + #[coverage(on)]
    |
 
-error: expected identifier, found `,`
-  --> $DIR/bad-syntax.rs:44:12
-   |
-LL | #[coverage(,off)]
-   |            ^ expected identifier
-   |
-help: remove this comma
-   |
-LL - #[coverage(,off)]
-LL + #[coverage(off)]
-   |
-
-error: multiple `coverage` attributes
-  --> $DIR/bad-syntax.rs:9:1
-   |
-LL | #[coverage(off)]
-   | ^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/bad-syntax.rs:10:1
-   |
-LL | #[coverage(off)]
-   | ^^^^^^^^^^^^^^^^
-
-error: multiple `coverage` attributes
-  --> $DIR/bad-syntax.rs:13:1
-   |
-LL | #[coverage(off)]
-   | ^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/bad-syntax.rs:14:1
-   |
-LL | #[coverage(on)]
-   | ^^^^^^^^^^^^^^^
-
 error: aborting due to 11 previous errors
 
+Some errors have detailed explanations: E0539, E0805.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs
index ffd9afe2ce1..8171dbbf692 100644
--- a/tests/ui/coverage-attr/name-value.rs
+++ b/tests/ui/coverage-attr/name-value.rs
@@ -20,7 +20,6 @@ mod my_mod_inner {
 
 #[coverage = "off"]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR [E0788]
 struct MyStruct;
 
 #[coverage = "off"]
@@ -28,22 +27,18 @@ struct MyStruct;
 impl MyStruct {
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     const X: u32 = 7;
 }
 
 #[coverage = "off"]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR [E0788]
 trait MyTrait {
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     const X: u32;
 
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     type T;
 }
 
@@ -52,12 +47,10 @@ trait MyTrait {
 impl MyTrait for MyStruct {
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     const X: u32 = 8;
 
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     type T = ();
 }
 
diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr
index f24db78415e..a838ec5df8e 100644
--- a/tests/ui/coverage-attr/name-value.stderr
+++ b/tests/ui/coverage-attr/name-value.stderr
@@ -1,10 +1,10 @@
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/name-value.rs:12:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = "off"]
 LL + #[coverage(off)]
@@ -13,28 +13,28 @@ LL - #[coverage = "off"]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/name-value.rs:17:5
    |
 LL |     #![coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #![coverage = "off"]
-LL +     #![coverage(off)]
+LL +     #[coverage(off)]
    |
 LL -     #![coverage = "off"]
-LL +     #![coverage(on)]
+LL +     #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/name-value.rs:21:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = "off"]
 LL + #[coverage(off)]
@@ -43,13 +43,13 @@ LL - #[coverage = "off"]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:26:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:25:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = "off"]
 LL + #[coverage(off)]
@@ -58,13 +58,13 @@ LL - #[coverage = "off"]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:29:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:28:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[coverage = "off"]
 LL +     #[coverage(off)]
@@ -73,13 +73,13 @@ LL -     #[coverage = "off"]
 LL +     #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:35:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:33:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = "off"]
 LL + #[coverage(off)]
@@ -88,13 +88,13 @@ LL - #[coverage = "off"]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:39:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:36:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[coverage = "off"]
 LL +     #[coverage(off)]
@@ -103,13 +103,13 @@ LL -     #[coverage = "off"]
 LL +     #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:44:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:40:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[coverage = "off"]
 LL +     #[coverage(off)]
@@ -118,13 +118,13 @@ LL -     #[coverage = "off"]
 LL +     #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:50:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:45:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = "off"]
 LL + #[coverage(off)]
@@ -133,13 +133,13 @@ LL - #[coverage = "off"]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:53:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:48:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[coverage = "off"]
 LL +     #[coverage(off)]
@@ -148,13 +148,13 @@ LL -     #[coverage = "off"]
 LL +     #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:58:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:52:5
    |
 LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[coverage = "off"]
 LL +     #[coverage(off)]
@@ -163,13 +163,13 @@ LL -     #[coverage = "off"]
 LL +     #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:64:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/name-value.rs:57:1
    |
 LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage = "off"]
 LL + #[coverage(off)]
@@ -178,87 +178,6 @@ LL - #[coverage = "off"]
 LL + #[coverage(on)]
    |
 
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:21:1
-   |
-LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
-...
-LL | struct MyStruct;
-   | ---------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:35:1
-   |
-LL |   #[coverage = "off"]
-   |   ^^^^^^^^^^^^^^^^^^^
-...
-LL | / trait MyTrait {
-LL | |     #[coverage = "off"]
-...  |
-LL | |     type T;
-LL | | }
-   | |_- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:39:5
-   |
-LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
-...
-LL |     const X: u32;
-   |     ------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:44:5
-   |
-LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
-...
-LL |     type T;
-   |     ------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:29:5
-   |
-LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
-...
-LL |     const X: u32 = 7;
-   |     ----------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:53:5
-   |
-LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
-...
-LL |     const X: u32 = 8;
-   |     ----------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/name-value.rs:58:5
-   |
-LL |     #[coverage = "off"]
-   |     ^^^^^^^^^^^^^^^^^^^
-...
-LL |     type T = ();
-   |     ------------ not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error: aborting due to 19 previous errors
+error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0788`.
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/coverage-attr/subword.stderr b/tests/ui/coverage-attr/subword.stderr
index a5d1a492181..32a09a10c84 100644
--- a/tests/ui/coverage-attr/subword.stderr
+++ b/tests/ui/coverage-attr/subword.stderr
@@ -1,10 +1,12 @@
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/subword.rs:8:1
    |
 LL | #[coverage(yes(milord))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^-----------^^
+   |            |
+   |            valid arguments are `on` or `off`
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(yes(milord))]
 LL + #[coverage(off)]
@@ -13,13 +15,15 @@ LL - #[coverage(yes(milord))]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/subword.rs:11:1
    |
 LL | #[coverage(no(milord))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^----------^^
+   |            |
+   |            valid arguments are `on` or `off`
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(no(milord))]
 LL + #[coverage(off)]
@@ -28,13 +32,15 @@ LL - #[coverage(no(milord))]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/subword.rs:14:1
    |
 LL | #[coverage(yes = "milord")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^--------------^^
+   |            |
+   |            valid arguments are `on` or `off`
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(yes = "milord")]
 LL + #[coverage(off)]
@@ -43,13 +49,15 @@ LL - #[coverage(yes = "milord")]
 LL + #[coverage(on)]
    |
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/subword.rs:17:1
    |
 LL | #[coverage(no = "milord")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^-------------^^
+   |            |
+   |            valid arguments are `on` or `off`
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[coverage(no = "milord")]
 LL + #[coverage(off)]
@@ -60,3 +68,4 @@ LL + #[coverage(on)]
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs
index d0f743938f3..81bd558b8b0 100644
--- a/tests/ui/coverage-attr/word-only.rs
+++ b/tests/ui/coverage-attr/word-only.rs
@@ -20,7 +20,6 @@ mod my_mod_inner {
 
 #[coverage]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR [E0788]
 struct MyStruct;
 
 #[coverage]
@@ -28,22 +27,18 @@ struct MyStruct;
 impl MyStruct {
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     const X: u32 = 7;
 }
 
 #[coverage]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR [E0788]
 trait MyTrait {
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     const X: u32;
 
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     type T;
 }
 
@@ -52,12 +47,10 @@ trait MyTrait {
 impl MyTrait for MyStruct {
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     const X: u32 = 8;
 
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR [E0788]
     type T = ();
 }
 
diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr
index 2773db9c857..dd161360a5c 100644
--- a/tests/ui/coverage-attr/word-only.stderr
+++ b/tests/ui/coverage-attr/word-only.stderr
@@ -1,240 +1,161 @@
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/word-only.rs:12:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/word-only.rs:17:5
    |
 LL |     #![coverage]
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #![coverage]
+LL +     #[coverage(off)]
+   |
+LL -     #![coverage]
+LL +     #[coverage(on)]
    |
-LL |     #![coverage(off)]
-   |                +++++
-LL |     #![coverage(on)]
-   |                ++++
 
-error: malformed `coverage` attribute input
+error[E0539]: malformed `coverage` attribute input
   --> $DIR/word-only.rs:21:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:26:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:25:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:29:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:28:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL |     #[coverage(off)]
    |               +++++
 LL |     #[coverage(on)]
    |               ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:35:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:33:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:39:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:36:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL |     #[coverage(off)]
    |               +++++
 LL |     #[coverage(on)]
    |               ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:44:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:40:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL |     #[coverage(off)]
    |               +++++
 LL |     #[coverage(on)]
    |               ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:50:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:45:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:53:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:48:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL |     #[coverage(off)]
    |               +++++
 LL |     #[coverage(on)]
    |               ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:58:5
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:52:5
    |
 LL |     #[coverage]
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL |     #[coverage(off)]
    |               +++++
 LL |     #[coverage(on)]
    |               ++++
 
-error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:64:1
+error[E0539]: malformed `coverage` attribute input
+  --> $DIR/word-only.rs:57:1
    |
 LL | #[coverage]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL | #[coverage(off)]
    |           +++++
 LL | #[coverage(on)]
    |           ++++
 
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:21:1
-   |
-LL | #[coverage]
-   | ^^^^^^^^^^^
-...
-LL | struct MyStruct;
-   | ---------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:35:1
-   |
-LL |   #[coverage]
-   |   ^^^^^^^^^^^
-...
-LL | / trait MyTrait {
-LL | |     #[coverage]
-...  |
-LL | |     type T;
-LL | | }
-   | |_- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:39:5
-   |
-LL |     #[coverage]
-   |     ^^^^^^^^^^^
-...
-LL |     const X: u32;
-   |     ------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:44:5
-   |
-LL |     #[coverage]
-   |     ^^^^^^^^^^^
-...
-LL |     type T;
-   |     ------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:29:5
-   |
-LL |     #[coverage]
-   |     ^^^^^^^^^^^
-...
-LL |     const X: u32 = 7;
-   |     ----------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:53:5
-   |
-LL |     #[coverage]
-   |     ^^^^^^^^^^^
-...
-LL |     const X: u32 = 8;
-   |     ----------------- not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error[E0788]: coverage attribute not allowed here
-  --> $DIR/word-only.rs:58:5
-   |
-LL |     #[coverage]
-   |     ^^^^^^^^^^^
-...
-LL |     type T = ();
-   |     ------------ not a function, impl block, or module
-   |
-   = help: coverage attribute can be applied to a function (with body), impl block, or module
-
-error: aborting due to 19 previous errors
+error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0788`.
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
index 5df2c687bdd..c0d568eb538 100644
--- a/tests/ui/deduplicate-diagnostics.deduplicate.stderr
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr
@@ -1,11 +1,11 @@
 error[E0452]: malformed lint attribute input
-  --> $DIR/deduplicate-diagnostics.rs:8:8
+  --> $DIR/deduplicate-diagnostics.rs:10:8
    |
 LL | #[deny("literal")]
    |        ^^^^^^^^^ bad attribute argument
 
 error: cannot find derive macro `Unresolved` in this scope
-  --> $DIR/deduplicate-diagnostics.rs:4:10
+  --> $DIR/deduplicate-diagnostics.rs:6:10
    |
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
diff --git a/tests/ui/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
index 48e2ba7b86a..74d7066293f 100644
--- a/tests/ui/deduplicate-diagnostics.duplicate.stderr
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr
@@ -1,17 +1,17 @@
 error[E0452]: malformed lint attribute input
-  --> $DIR/deduplicate-diagnostics.rs:8:8
+  --> $DIR/deduplicate-diagnostics.rs:10:8
    |
 LL | #[deny("literal")]
    |        ^^^^^^^^^ bad attribute argument
 
 error: cannot find derive macro `Unresolved` in this scope
-  --> $DIR/deduplicate-diagnostics.rs:4:10
+  --> $DIR/deduplicate-diagnostics.rs:6:10
    |
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
 
 error: cannot find derive macro `Unresolved` in this scope
-  --> $DIR/deduplicate-diagnostics.rs:4:10
+  --> $DIR/deduplicate-diagnostics.rs:6:10
    |
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | #[derive(Unresolved)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/deduplicate-diagnostics.rs:8:8
+  --> $DIR/deduplicate-diagnostics.rs:10:8
    |
 LL | #[deny("literal")]
    |        ^^^^^^^^^ bad attribute argument
@@ -27,7 +27,7 @@ LL | #[deny("literal")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/deduplicate-diagnostics.rs:8:8
+  --> $DIR/deduplicate-diagnostics.rs:10:8
    |
 LL | #[deny("literal")]
    |        ^^^^^^^^^ bad attribute argument
diff --git a/tests/ui/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
index 299c1f5f461..48705266e35 100644
--- a/tests/ui/deduplicate-diagnostics.rs
+++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs
@@ -1,3 +1,5 @@
+//! Test that `-Z deduplicate-diagnostics` flag properly deduplicates diagnostic messages.
+
 //@ revisions: duplicate deduplicate
 //@[deduplicate] compile-flags: -Z deduplicate-diagnostics=yes
 
diff --git a/tests/ui/error-codes/E0120.rs b/tests/ui/error-codes/E0120.rs
index 35f544fddfb..4e5cc7d6833 100644
--- a/tests/ui/error-codes/E0120.rs
+++ b/tests/ui/error-codes/E0120.rs
@@ -1,4 +1,4 @@
-trait MyTrait { fn foo() {} }
+trait MyTrait { fn foo(&self) {} }
 
 impl Drop for dyn MyTrait {
               //~^ ERROR E0120
diff --git a/tests/ui/expr/syntax-edge-cases-lint-clean.rs b/tests/ui/expr/weird-exprs.rs
index 7db92d46067..7db92d46067 100644
--- a/tests/ui/expr/syntax-edge-cases-lint-clean.rs
+++ b/tests/ui/expr/weird-exprs.rs
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/extern/extern-types-size_of_val.rs b/tests/ui/extern/extern-types-size_of_val.rs
index 3ff51b9b6b0..875ae9a535a 100644
--- a/tests/ui/extern/extern-types-size_of_val.rs
+++ b/tests/ui/extern/extern-types-size_of_val.rs
@@ -1,4 +1,4 @@
-//@ check-fail
+//@ check-pass
 #![feature(extern_types)]
 
 use std::mem::{align_of_val, size_of_val};
@@ -11,7 +11,5 @@ fn main() {
     let x: &A = unsafe { &*(1usize as *const A) };
 
     size_of_val(x);
-    //~^ ERROR the size for values of type `A` cannot be known
     align_of_val(x);
-    //~^ ERROR the size for values of type `A` cannot be known
 }
diff --git a/tests/ui/extern/extern-types-size_of_val.stderr b/tests/ui/extern/extern-types-size_of_val.stderr
deleted file mode 100644
index 8678c6c3d60..00000000000
--- a/tests/ui/extern/extern-types-size_of_val.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0277]: the size for values of type `A` cannot be known
-  --> $DIR/extern-types-size_of_val.rs:13:17
-   |
-LL |     size_of_val(x);
-   |     ----------- ^ the trait `MetaSized` is not implemented for `A`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = note: the trait bound `A: MetaSized` is not satisfied
-note: required by a bound in `std::mem::size_of_val`
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
-help: consider borrowing here
-   |
-LL |     size_of_val(&x);
-   |                 +
-LL |     size_of_val(&mut x);
-   |                 ++++
-
-error[E0277]: the size for values of type `A` cannot be known
-  --> $DIR/extern-types-size_of_val.rs:15:18
-   |
-LL |     align_of_val(x);
-   |     ------------ ^ the trait `MetaSized` is not implemented for `A`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = note: the trait bound `A: MetaSized` is not satisfied
-note: required by a bound in `std::mem::align_of_val`
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
-help: consider borrowing here
-   |
-LL |     align_of_val(&x);
-   |                  +
-LL |     align_of_val(&mut x);
-   |                  ++++
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/extern/extern-types-unsized.rs b/tests/ui/extern/extern-types-unsized.rs
index 46cdc24e083..94a222a7e7e 100644
--- a/tests/ui/extern/extern-types-unsized.rs
+++ b/tests/ui/extern/extern-types-unsized.rs
@@ -27,9 +27,7 @@ fn main() {
 
     assert_sized::<Bar<A>>();
     //~^ ERROR the size for values of type
-    //~| ERROR the size for values of type
 
     assert_sized::<Bar<Bar<A>>>();
     //~^ ERROR the size for values of type
-    //~| ERROR the size for values of type
 }
diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr
index 43dd9800d6d..a587d4dda55 100644
--- a/tests/ui/extern/extern-types-unsized.stderr
+++ b/tests/ui/extern/extern-types-unsized.stderr
@@ -59,21 +59,8 @@ help: consider relaxing the implicit `Sized` restriction
 LL | fn assert_sized<T: ?Sized>() {}
    |                  ++++++++
 
-error[E0277]: the size for values of type `A` cannot be known
-  --> $DIR/extern-types-unsized.rs:28:20
-   |
-LL |     assert_sized::<Bar<A>>();
-   |                    ^^^^^^ doesn't have a known size
-   |
-   = help: the trait `MetaSized` is not implemented for `A`
-note: required by a bound in `Bar`
-  --> $DIR/extern-types-unsized.rs:14:12
-   |
-LL | struct Bar<T: ?Sized> {
-   |            ^ required by this bound in `Bar`
-
 error[E0277]: the size for values of type `A` cannot be known at compilation time
-  --> $DIR/extern-types-unsized.rs:32:20
+  --> $DIR/extern-types-unsized.rs:31:20
    |
 LL |     assert_sized::<Bar<Bar<A>>>();
    |                    ^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -94,19 +81,6 @@ help: consider relaxing the implicit `Sized` restriction
 LL | fn assert_sized<T: ?Sized>() {}
    |                  ++++++++
 
-error[E0277]: the size for values of type `A` cannot be known
-  --> $DIR/extern-types-unsized.rs:32:20
-   |
-LL |     assert_sized::<Bar<Bar<A>>>();
-   |                    ^^^^^^^^^^^ doesn't have a known size
-   |
-   = help: the trait `MetaSized` is not implemented for `A`
-note: required by a bound in `Bar`
-  --> $DIR/extern-types-unsized.rs:14:12
-   |
-LL | struct Bar<T: ?Sized> {
-   |            ^ required by this bound in `Bar`
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/extern/unsized-extern-derefmove.rs b/tests/ui/extern/unsized-extern-derefmove.rs
index c02375266ab..39597a12fe1 100644
--- a/tests/ui/extern/unsized-extern-derefmove.rs
+++ b/tests/ui/extern/unsized-extern-derefmove.rs
@@ -7,14 +7,10 @@ extern "C" {
 }
 
 unsafe fn make_device() -> Box<Device> {
-//~^ ERROR the size for values of type `Device` cannot be known
     Box::from_raw(0 as *mut _)
-//~^ ERROR the size for values of type `Device` cannot be known
-//~| ERROR the size for values of type `Device` cannot be known
 }
 
 fn main() {
     let d: Device = unsafe { *make_device() };
 //~^ ERROR the size for values of type `Device` cannot be known
-//~| ERROR the size for values of type `Device` cannot be known
 }
diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr
index a9efc2e66e3..c43184d94e1 100644
--- a/tests/ui/extern/unsized-extern-derefmove.stderr
+++ b/tests/ui/extern/unsized-extern-derefmove.stderr
@@ -1,43 +1,5 @@
-error[E0277]: the size for values of type `Device` cannot be known
-  --> $DIR/unsized-extern-derefmove.rs:9:28
-   |
-LL | unsafe fn make_device() -> Box<Device> {
-   |                            ^^^^^^^^^^^ doesn't have a known size
-   |
-   = help: the trait `MetaSized` is not implemented for `Device`
-note: required by a bound in `Box`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-
-error[E0277]: the size for values of type `Device` cannot be known
-  --> $DIR/unsized-extern-derefmove.rs:11:19
-   |
-LL |     Box::from_raw(0 as *mut _)
-   |     ------------- ^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Device`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = note: the trait bound `Device: MetaSized` is not satisfied
-note: required by a bound in `Box::<T>::from_raw`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-help: consider borrowing here
-   |
-LL |     Box::from_raw(&(0 as *mut _))
-   |                   ++           +
-LL |     Box::from_raw(&mut (0 as *mut _))
-   |                   ++++++           +
-
-error[E0277]: the size for values of type `Device` cannot be known
-  --> $DIR/unsized-extern-derefmove.rs:11:5
-   |
-LL |     Box::from_raw(0 as *mut _)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
-   |
-   = help: the trait `MetaSized` is not implemented for `Device`
-note: required by a bound in `Box`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-
 error[E0277]: the size for values of type `Device` cannot be known at compilation time
-  --> $DIR/unsized-extern-derefmove.rs:17:9
+  --> $DIR/unsized-extern-derefmove.rs:14:9
    |
 LL |     let d: Device = unsafe { *make_device() };
    |         ^ doesn't have a size known at compile-time
@@ -49,16 +11,6 @@ help: consider borrowing here
 LL |     let d: &Device = unsafe { *make_device() };
    |            +
 
-error[E0277]: the size for values of type `Device` cannot be known
-  --> $DIR/unsized-extern-derefmove.rs:17:31
-   |
-LL |     let d: Device = unsafe { *make_device() };
-   |                               ^^^^^^^^^^^^^ doesn't have a known size
-   |
-   = help: the trait `MetaSized` is not implemented for `Device`
-note: required by a bound in `Box`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-
-error: aborting due to 5 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
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/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index d07201ebbd1..9740eaaf1e9 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -269,7 +269,13 @@ mod automatically_derived {
     #[automatically_derived] type T = S;
     //~^ WARN `#[automatically_derived]
 
+    #[automatically_derived] trait W { }
+    //~^ WARN `#[automatically_derived]
+
     #[automatically_derived] impl S { }
+    //~^ WARN `#[automatically_derived]
+
+    #[automatically_derived] impl W for S { }
 }
 
 #[no_mangle]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 5d7d1caeeab..9016ca1efa7 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -1,5 +1,5 @@
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     mod inner { #![macro_escape] }
    = help: try an outer attribute: `#[macro_use]`
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
@@ -198,14 +198,14 @@ note: the lint level is defined here
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on implementation blocks
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1
    |
 LL |   #[no_mangle]
    |   ^^^^^^^^^^^^
@@ -220,31 +220,31 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1
    |
 LL | #[reexport_test_harness_main = "2900"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:1
    |
 LL |   #[cold]
    |   ^^^^^^^
@@ -260,7 +260,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1
    |
 LL |   #[link_name = "1900"]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -276,7 +276,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:1
    |
 LL |   #[link_section = "1800"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -292,7 +292,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:1
    |
 LL |   #[link()]
    |   ^^^^^^^^^
@@ -308,55 +308,55 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[must_use]` has no effect when applied to a module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:595:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:608:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1
    |
 LL | #[windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1
    |
 LL | #[no_builtins]
    | ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -417,6 +417,14 @@ LL | #![cold]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:85:12
+   |
+LL | #![feature(rust1)]
+   |            ^^^^^
+   |
+   = note: `#[warn(stable_features)]` on by default
+
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5
    |
@@ -495,32 +503,44 @@ warning: `#[path]` only has an effect on modules
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on implementation blocks
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on implementation blocks
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on implementation blocks
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on implementation blocks
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
+   |
+LL |     #[automatically_derived] trait W { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[automatically_derived]` only has an effect on trait implementation blocks
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
+   |
+LL |     #[automatically_derived] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:17
    |
 LL |     mod inner { #![no_mangle] }
    |     ------------^^^^^^^^^^^^^-- not a free function, impl method or static
@@ -528,7 +548,7 @@ LL |     mod inner { #![no_mangle] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -536,7 +556,7 @@ LL |     #[no_mangle] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:292:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:298:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -544,7 +564,7 @@ LL |     #[no_mangle] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:297:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^ ---------- not a free function, impl method or static
@@ -552,7 +572,7 @@ LL |     #[no_mangle] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:309:9
    |
 LL |         #[no_mangle] fn foo();
    |         ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -560,7 +580,7 @@ LL |         #[no_mangle] fn foo();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:308:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:9
    |
 LL |         #[no_mangle] fn bar() {}
    |         ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -568,163 +588,163 @@ LL |         #[no_mangle] fn bar() {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:17
    |
 LL |     mod inner { #![cold] }
    |     ------------^^^^^^^^-- not a function definition
@@ -732,7 +752,7 @@ LL |     mod inner { #![cold] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^ --------- not a function definition
@@ -740,7 +760,7 @@ LL |     #[cold] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^ ----------- not a function definition
@@ -748,7 +768,7 @@ LL |     #[cold] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^ ---------- not a function definition
@@ -756,7 +776,7 @@ LL |     #[cold] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -766,13 +786,13 @@ LL |     extern "C" { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 help: try `#[link(name = "1900")]` instead
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static
@@ -780,7 +800,7 @@ LL |     mod inner { #![link_name="1900"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -788,7 +808,7 @@ LL |     #[link_name = "1900"] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static
@@ -796,7 +816,7 @@ LL |     #[link_name = "1900"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static
@@ -804,7 +824,7 @@ LL |     #[link_name = "1900"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -812,7 +832,7 @@ LL |     #[link_name = "1900"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static
@@ -820,7 +840,7 @@ LL |     mod inner { #![link_section="1800"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:531:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static
@@ -828,7 +848,7 @@ LL |     #[link_section = "1800"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:530:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static
@@ -836,7 +856,7 @@ LL |     #[link_section = "1800"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static
@@ -844,7 +864,7 @@ LL |     #[link_section = "1800"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:556:17
    |
 LL |     mod inner { #![link()] }
    |     ------------^^^^^^^^^^-- not an `extern` block
@@ -852,7 +872,7 @@ LL |     mod inner { #![link()] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5
    |
 LL |     #[link()] fn f() { }
    |     ^^^^^^^^^ ---------- not an `extern` block
@@ -860,7 +880,7 @@ LL |     #[link()] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:566:5
    |
 LL |     #[link()] struct S;
    |     ^^^^^^^^^ --------- not an `extern` block
@@ -868,7 +888,7 @@ LL |     #[link()] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:5
    |
 LL |     #[link()] type T = S;
    |     ^^^^^^^^^ ----------- not an `extern` block
@@ -876,7 +896,7 @@ LL |     #[link()] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5
    |
 LL |     #[link()] impl S { }
    |     ^^^^^^^^^ ---------- not an `extern` block
@@ -884,7 +904,7 @@ LL |     #[link()] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:575:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5
    |
 LL |     #[link()] extern "Rust" {}
    |     ^^^^^^^^^
@@ -892,270 +912,262 @@ LL |     #[link()] extern "Rust" {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[must_use]` has no effect when applied to a module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:597:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17
    |
 LL |     mod inner { #![must_use] }
    |                 ^^^^^^^^^^^^
 
 warning: `#[must_use]` has no effect when applied to a type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5
    |
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
 
-warning: `#[must_use]` has no effect when applied to an implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:5
+warning: `#[must_use]` has no effect when applied to an inherent implementation block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5
    |
 LL |     #[must_use] impl S { }
    |     ^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17
    |
 LL |     mod inner { #![windows_subsystem="windows"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17
    |
 LL |     mod inner { #![no_builtins] }
    |                 ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
    |
 LL |     #[no_builtins] fn f() { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
    |
 LL |     #[no_builtins] struct S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
    |
 LL |     #[no_builtins] type T = S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5
    |
 LL |     #[no_builtins] impl S { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:85:12
-   |
-LL | #![feature(rust1)]
-   |            ^^^^^
-   |
-   = note: `#[warn(stable_features)]` on by default
-
-warning: 171 warnings emitted
+warning: 173 warnings emitted
 
diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
index 319056a9c88..d599523c727 100644
--- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
+++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
@@ -1,31 +1,31 @@
 error: can't mark as unstable using an already stable feature
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
    |
-LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | const fn my_fun() {}
    | -------------------- the stability attribute annotates this item
    |
 help: consider removing the attribute
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
    |
-LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: can't mark as unstable using an already stable feature
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
    |
+LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
 LL | const fn my_fun() {}
    | -------------------- the stability attribute annotates this item
    |
 help: consider removing the attribute
-  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+  --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
    |
-LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/log-poly.rs b/tests/ui/fmt/println-debug-different-types.rs
index 64994a55817..9e21be1f03f 100644
--- a/tests/ui/log-poly.rs
+++ b/tests/ui/fmt/println-debug-different-types.rs
@@ -1,8 +1,10 @@
+//! Smoke test for println!() with debug format specifiers.
+
 //@ run-pass
 
 #[derive(Debug)]
 enum Numbers {
-    Three
+    Three,
 }
 
 pub fn main() {
diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr
deleted file mode 100644
index ff82aebfef9..00000000000
--- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr
+++ /dev/null
@@ -1,48 +0,0 @@
-error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:15:5
-   |
-LL | /     async { // a coroutine checked for autotrait impl `Send`
-LL | |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
-LL | |         async {}.await; // a yield point
-LL | |     }
-   | |_____^
-   |
-   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:22:5
-   |
-LL | /     async { // a coroutine checked for autotrait impl `Send`
-LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-LL | |         async {}.await; // a yield point
-LL | |     }
-   | |_____^
-   |
-   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-error: lifetime may not live long enough
-  --> $DIR/issue-100013.rs:23:17
-   |
-LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
-   |          --  -- lifetime `'b` defined here
-   |          |
-   |          lifetime `'a` defined here
-LL |     async { // a coroutine checked for autotrait impl `Send`
-LL |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
-   |
-   = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:29:5
-   |
-LL | /     async { // a coroutine checked for autotrait impl `Send`
-LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-LL | |         async {}.await; // a yield point
-LL | |     }
-   | |_____^
-   |
-   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr
new file mode 100644
index 00000000000..8b62fb6a254
--- /dev/null
+++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.no_assumptions.stderr
@@ -0,0 +1,24 @@
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-coroutine-param-outlives-2.rs:14:5
+   |
+LL | /     async { // a coroutine checked for autotrait impl `Send`
+LL | |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime bound not satisfied
+  --> $DIR/higher-ranked-coroutine-param-outlives-2.rs:21:5
+   |
+LL | /     async { // a coroutine checked for autotrait impl `Send`
+LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | |         async {}.await; // a yield point
+LL | |     }
+   | |_____^
+   |
+   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs
index ac72c29c03b..a5ed162d62c 100644
--- a/tests/ui/generic-associated-types/bugs/issue-100013.rs
+++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs
@@ -1,9 +1,8 @@
-//@ check-fail
-//@ known-bug: #100013
 //@ edition: 2021
-
-// We really should accept this, but we need implied bounds between the regions
-// in a coroutine interior.
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
 
 pub trait FutureIterator {
     type Future<'s, 'cx>: Send
@@ -18,14 +17,7 @@ fn call<I: FutureIterator>() -> impl Send {
     }
 }
 
-fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
-    async { // a coroutine checked for autotrait impl `Send`
-        let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-        async {}.await; // a yield point
-    }
-}
-
-fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+fn call2<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
     async { // a coroutine checked for autotrait impl `Send`
         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
         async {}.await; // a yield point
diff --git a/tests/ui/generic-associated-types/issue-92096.stderr b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr
index b9a16cf184e..f747ba9a733 100644
--- a/tests/ui/generic-associated-types/issue-92096.stderr
+++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.no_assumptions.stderr
@@ -1,5 +1,5 @@
 error: `C` does not live long enough
-  --> $DIR/issue-92096.rs:17:5
+  --> $DIR/higher-ranked-coroutine-param-outlives.rs:21:5
    |
 LL |     async move { c.connect().await }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs
new file mode 100644
index 00000000000..5f683bd82fa
--- /dev/null
+++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs
@@ -0,0 +1,24 @@
+//@ edition:2018
+//@ revisions: assumptions no_assumptions
+//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
+//@[assumptions] check-pass
+//@[no_assumptions] known-bug: #110338
+
+use std::future::Future;
+
+trait Client {
+    type Connecting<'a>: Future + Send
+    where
+        Self: 'a;
+
+    fn connect(&'_ self) -> Self::Connecting<'_>;
+}
+
+fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+where
+    C: Client + Send + Sync,
+{
+    async move { c.connect().await }
+}
+
+fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-92096.rs b/tests/ui/generic-associated-types/issue-92096.rs
deleted file mode 100644
index a34c4179584..00000000000
--- a/tests/ui/generic-associated-types/issue-92096.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@ edition:2018
-
-use std::future::Future;
-
-trait Client {
-    type Connecting<'a>: Future + Send
-    where
-        Self: 'a;
-
-    fn connect(&'_ self) -> Self::Connecting<'_>;
-}
-
-fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-where
-    C: Client + Send + Sync,
-{
-    async move { c.connect().await }
-    //~^ ERROR `C` does not live long enough
-    //
-    // FIXME(#71723). This is because we infer at some point a value of
-    //
-    // impl Future<Output = <C as Client>::Connection<'_>>
-    //
-    // and then we somehow fail the WF check because `where C: 'a` is not known,
-    // but I'm not entirely sure how that comes about.
-}
-
-fn main() {}
diff --git a/tests/ui/impl-trait/call_method_without_import.no_import.stderr b/tests/ui/impl-trait/call_method_without_import.no_import.stderr
index e59409ea27e..dbac74b2247 100644
--- a/tests/ui/impl-trait/call_method_without_import.no_import.stderr
+++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr
@@ -22,15 +22,10 @@ LL |         x.fmt(f);
    = help: items from traits can only be used if the trait is in scope
 help: the following traits which provide `fmt` are implemented but not in scope; perhaps you want to import one of them
    |
-LL + use std::fmt::Binary;
-   |
 LL + use std::fmt::Debug;
    |
-LL + use std::fmt::Display;
-   |
-LL + use std::fmt::LowerExp;
+LL + use std::fmt::Pointer;
    |
-   = and 5 other candidates
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/in-bindings/implicit-sized.rs b/tests/ui/impl-trait/in-bindings/implicit-sized.rs
new file mode 100644
index 00000000000..2f16db94189
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/implicit-sized.rs
@@ -0,0 +1,19 @@
+#![feature(impl_trait_in_bindings)]
+
+trait Trait {}
+impl<T: ?Sized> Trait for T {}
+
+fn doesnt_work() {
+    let x: &impl Trait = "hi";
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+}
+
+fn works() {
+    let x: &(impl Trait + ?Sized) = "hi";
+    // No implicit sized.
+
+    let x: &impl Trait = &();
+    // Is actually sized.
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-bindings/implicit-sized.stderr b/tests/ui/impl-trait/in-bindings/implicit-sized.stderr
new file mode 100644
index 00000000000..465a928cf86
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/implicit-sized.stderr
@@ -0,0 +1,11 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/implicit-sized.rs:7:13
+   |
+LL |     let x: &impl Trait = "hi";
+   |             ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/issues/issue-55872-3.rs b/tests/ui/impl-trait/issues/issue-55872-3.rs
index 698e7f36234..763b4b9fd32 100644
--- a/tests/ui/impl-trait/issues/issue-55872-3.rs
+++ b/tests/ui/impl-trait/issues/issue-55872-3.rs
@@ -14,6 +14,7 @@ impl<S> Bar for S {
     fn foo<T>() -> Self::E {
         //~^ ERROR : Copy` is not satisfied [E0277]
         //~| ERROR type parameter `T` is part of concrete type
+        //~| ERROR type parameter `T` is part of concrete type
         async {}
     }
 }
diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr
index 3281dcc3501..ce2dd7f02b4 100644
--- a/tests/ui/impl-trait/issues/issue-55872-3.stderr
+++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr
@@ -1,11 +1,11 @@
-error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}: Copy` is not satisfied
+error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied
   --> $DIR/issue-55872-3.rs:14:20
    |
 LL |     fn foo<T>() -> Self::E {
-   |                    ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}`
+   |                    ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}`
 ...
 LL |         async {}
-   |         -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` here
+   |         -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` here
 
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
   --> $DIR/issue-55872-3.rs:14:20
@@ -13,6 +13,14 @@ error: type parameter `T` is part of concrete type but not used in parameter lis
 LL |     fn foo<T>() -> Self::E {
    |                    ^^^^^^^
 
-error: aborting due to 2 previous errors
+error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+  --> $DIR/issue-55872-3.rs:14:20
+   |
+LL |     fn foo<T>() -> Self::E {
+   |                    ^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr
index 061c9bd8f35..b376f205411 100644
--- a/tests/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr
@@ -9,12 +9,8 @@ help: the following traits which provide `method` are implemented but not in sco
    |
 LL + use foo::Bar;
    |
-LL + use no_method_suggested_traits::Reexported;
-   |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
-LL + use no_method_suggested_traits::qux::PrivPub;
-   |
 help: there is a method `method2` with a similar name
    |
 LL |     1u32.method2();
@@ -31,12 +27,8 @@ help: the following traits which provide `method` are implemented but not in sco
    |
 LL + use foo::Bar;
    |
-LL + use no_method_suggested_traits::Reexported;
-   |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
-LL + use no_method_suggested_traits::qux::PrivPub;
-   |
 help: there is a method `method2` with a similar name
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method2();
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/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
index 1ac3c593dbe..1b8a5d4ca99 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
     v.into_iter()
 }
 
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
index b9d8674992c..3651226e0c3 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
@@ -1,11 +1,12 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31
    |
 LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
-   |                               ^^ this lifetime flows to the output               ---- the lifetime gets resolved as `'a`
+   |                               ^^ the lifetime is named here                      ---- the same lifetime is elided here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &'a u32)> {
    |                                                                                   ++
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/layout/unconstrained-param-ice-137308.rs b/tests/ui/layout/unconstrained-param-ice-137308.rs
index 03b7e759960..d05e6e1fd3f 100644
--- a/tests/ui/layout/unconstrained-param-ice-137308.rs
+++ b/tests/ui/layout/unconstrained-param-ice-137308.rs
@@ -17,4 +17,3 @@ impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
 #[rustc_layout(debug)]
 struct S([u8; <u8 as A>::B]);
 //~^ ERROR: the type has an unknown layout
-//~| ERROR: type annotations needed
diff --git a/tests/ui/layout/unconstrained-param-ice-137308.stderr b/tests/ui/layout/unconstrained-param-ice-137308.stderr
index 82cd1217c49..615c131eb90 100644
--- a/tests/ui/layout/unconstrained-param-ice-137308.stderr
+++ b/tests/ui/layout/unconstrained-param-ice-137308.stderr
@@ -4,19 +4,12 @@ error[E0207]: the type parameter `C` is not constrained by the impl trait, self
 LL | impl<C: ?Sized> A for u8 {
    |      ^ unconstrained type parameter
 
-error[E0282]: type annotations needed
-  --> $DIR/unconstrained-param-ice-137308.rs:18:16
-   |
-LL | struct S([u8; <u8 as A>::B]);
-   |                ^^ cannot infer type for type parameter `C`
-
 error: the type has an unknown layout
   --> $DIR/unconstrained-param-ice-137308.rs:18:1
    |
 LL | struct S([u8; <u8 as A>::B]);
    | ^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0207, E0282.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs
new file mode 100644
index 00000000000..34803c8c103
--- /dev/null
+++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs
@@ -0,0 +1,18 @@
+// The opaque type collector used to expand free alias types (in situ) without guarding against
+// endlessly recursing aliases which lead to the compiler overflowing its stack in certain
+// situations.
+//
+// In most situations we wouldn't even reach the collector when there's an overflow because we
+// would've already bailed out early during the item's wfcheck due to the normalization failure.
+//
+// In the case below however, while collecting the opaque types defined by the AnonConst, we
+// descend into its nested items (here: type alias `Recur`) to acquire their opaque types --
+// meaning we get there before we wfcheck `Recur`.
+//
+// issue: <https://github.com/rust-lang/rust/issues/131994>
+#![feature(lazy_type_alias)]
+#![expect(incomplete_features)]
+
+struct Hold([(); { type Recur = Recur; 0 }]); //~ ERROR overflow normalizing the type alias `Recur`
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr
new file mode 100644
index 00000000000..e93fcd03a96
--- /dev/null
+++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr
@@ -0,0 +1,11 @@
+error[E0275]: overflow normalizing the type alias `Recur`
+  --> $DIR/opaq-ty-collection-infinite-recur.rs:16:20
+   |
+LL | struct Hold([(); { type Recur = Recur; 0 }]);
+   |                    ^^^^^^^^^^
+   |
+   = note: in case this is a recursive type alias, consider using a struct, enum, or union instead
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
index 1804003d367..9162a38f510 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs
@@ -4,7 +4,7 @@ struct Foo;
 
 impl Foo {
     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         unsafe { &mut *(x as *mut _) }
     }
 }
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
index 7c7411651d0..5a7a5a6ebf9 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr
@@ -1,17 +1,18 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/example-from-issue48686.rs:6:21
    |
 LL |     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
-   |                     ^^^^^^^                      ------- the lifetime gets resolved as `'static`
+   |                     ^^^^^^^                      ------- the same lifetime is elided here
    |                     |
-   |                     this lifetime flows to the output
+   |                     the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/example-from-issue48686.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 {
    |                                                   +++++++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
index 3d5aab5c829..ecc790be5a0 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs
@@ -1,26 +1,26 @@
 #![deny(mismatched_lifetime_syntaxes)]
 
 fn ampersand<'a>(x: &'a u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
 struct Brackets<'a>(&'a u8);
 
 fn brackets<'a>(x: &'a u8) -> Brackets {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Brackets(x)
 }
 
 struct Comma<'a, T>(&'a T);
 
 fn comma<'a>(x: &'a u8) -> Comma<u8> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Comma(x)
 }
 
 fn underscore<'a>(x: &'a u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
index 681b3c97052..af56a0a0ea5 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr
@@ -1,56 +1,60 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:3:22
    |
 LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
-   |                      ^^        --- the lifetime gets resolved as `'a`
+   |                      ^^        --- the same lifetime is elided here
    |                      |
-   |                      this lifetime flows to the output
+   |                      the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/missing-lifetime-kind.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 {
    |                                 ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:10:21
    |
 LL | fn brackets<'a>(x: &'a u8) -> Brackets {
-   |                     ^^        -------- the lifetime gets resolved as `'a`
+   |                     ^^        -------- the same lifetime is hidden here
    |                     |
-   |                     this lifetime flows to the output
+   |                     the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> {
    |                                       ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:17:18
    |
 LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
-   |                  ^^        --------- the lifetime gets resolved as `'a`
+   |                  ^^        --------- the same lifetime is hidden here
    |                  |
-   |                  this lifetime flows to the output
+   |                  the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> {
    |                                  +++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/missing-lifetime-kind.rs:22:23
    |
 LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
-   |                       ^^         -- the lifetime gets resolved as `'a`
+   |                       ^^         -- the same lifetime is elided here
    |                       |
-   |                       this lifetime flows to the output
+   |                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 {
 LL + fn underscore<'a>(x: &'a u8) -> &'a u8 {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
index cc398ab7888..449b2a3c0a8 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs
@@ -6,13 +6,13 @@
 #[warn(mismatched_lifetime_syntaxes)]
 mod foo {
     fn bar(x: &'static u8) -> &u8 {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         x
     }
 
     #[deny(mismatched_lifetime_syntaxes)]
     fn baz(x: &'static u8) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         x
     }
 }
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
index da691225c17..cf0a29678fa 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr
@@ -1,35 +1,37 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/not-tied-to-crate.rs:8:16
    |
 LL |     fn bar(x: &'static u8) -> &u8 {
-   |                ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                ^^^^^^^        --- the same lifetime is elided here
    |                |
-   |                this lifetime flows to the output
+   |                the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/not-tied-to-crate.rs:6:8
    |
 LL | #[warn(mismatched_lifetime_syntaxes)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     fn bar(x: &'static u8) -> &'static u8 {
    |                                +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/not-tied-to-crate.rs:14:16
    |
 LL |     fn baz(x: &'static u8) -> &u8 {
-   |                ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                ^^^^^^^        --- the same lifetime is elided here
    |                |
-   |                this lifetime flows to the output
+   |                the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/not-tied-to-crate.rs:13:12
    |
 LL |     #[deny(mismatched_lifetime_syntaxes)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL |     fn baz(x: &'static u8) -> &'static u8 {
    |                                +++++++
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
index 47ae258f138..c41cf44e1c5 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs
@@ -14,26 +14,26 @@ impl Trait for () {
 }
 
 fn ampersand(x: &'static u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
 struct Brackets<'a>(&'a u8);
 
 fn brackets(x: &'static u8) -> Brackets {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Brackets(x)
 }
 
 struct Comma<'a, T>(&'a T);
 
 fn comma(x: &'static u8) -> Comma<u8> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     Comma(x)
 }
 
 fn underscore(x: &'static u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     x
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
index 5b9a986bcbe..d60bec6f7e4 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr
@@ -1,56 +1,60 @@
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:16:18
    |
 LL | fn ampersand(x: &'static u8) -> &u8 {
-   |                  ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                  ^^^^^^^        --- the same lifetime is elided here
    |                  |
-   |                  this lifetime flows to the output
+   |                  the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/static.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'static`
+help: consistently use `'static`
    |
 LL | fn ampersand(x: &'static u8) -> &'static u8 {
    |                                  +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:23:17
    |
 LL | fn brackets(x: &'static u8) -> Brackets {
-   |                 ^^^^^^^        -------- the lifetime gets resolved as `'static`
+   |                 ^^^^^^^        -------- the same lifetime is hidden here
    |                 |
-   |                 this lifetime flows to the output
+   |                 the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL | fn brackets(x: &'static u8) -> Brackets<'static> {
    |                                        +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: hiding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:30:14
    |
 LL | fn comma(x: &'static u8) -> Comma<u8> {
-   |              ^^^^^^^        --------- the lifetime gets resolved as `'static`
+   |              ^^^^^^^        --------- the same lifetime is hidden here
    |              |
-   |              this lifetime flows to the output
+   |              the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL | fn comma(x: &'static u8) -> Comma<'static, u8> {
    |                                   ++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
+error: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/static.rs:35:19
    |
 LL | fn underscore(x: &'static u8) -> &'_ u8 {
-   |                   ^^^^^^^         -- the lifetime gets resolved as `'static`
+   |                   ^^^^^^^         -- the same lifetime is elided here
    |                   |
-   |                   this lifetime flows to the output
+   |                   the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL - fn underscore(x: &'static u8) -> &'_ u8 {
 LL + fn underscore(x: &'static u8) -> &'static u8 {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
index b98423afb17..f6260c47202 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
@@ -5,109 +5,111 @@ struct ContainsLifetime<'a>(&'a u8);
 
 struct S(u8);
 
+// ref to ref
+
 fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v
 }
 
 fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v
 }
 
-// ---
+// path to path
 
 fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v
 }
 
 fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v
 }
 
 fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     v
 }
 
 fn explicit_bound_path_to_explicit_anonymous_path<'a>(
     v: ContainsLifetime<'a>,
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
 ) -> ContainsLifetime<'_> {
     v
 }
 
-// ---
+// ref to path
 
 fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     ContainsLifetime(v)
 }
 
 fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     ContainsLifetime(v)
 }
 
-// ---
+// path to ref
 
 fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v.0
 }
 
 fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     v.0
 }
 
 fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v.0
 }
 
 fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
-    //~^ ERROR lifetime flowing from input to output with different syntax
+    //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     v.0
 }
 
 impl S {
     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         &self.0
     }
 
     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         &self.0
     }
 
     // ---
 
     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 
     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 
     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         ContainsLifetime(&self.0)
     }
 }
@@ -122,43 +124,43 @@ mod static_suggestions {
     struct S(u8);
 
     fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         v
     }
 
     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         v
     }
 
     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
         ContainsLifetime(v)
     }
 
     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         ContainsLifetime(v)
     }
 
     impl S {
         fn static_ref_to_implicit_ref(&'static self) -> &u8 {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             &self.0
         }
 
         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             &self.0
         }
 
         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's named elsewhere is confusing
             ContainsLifetime(&self.0)
         }
 
         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR eliding a lifetime that's named elsewhere is confusing
             ContainsLifetime(&self.0)
         }
     }
@@ -170,23 +172,23 @@ mod impl_trait {
     struct ContainsLifetime<'a>(&'a u8);
 
     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         move || _ = v
     }
 
     fn explicit_bound_path_to_impl_trait_precise_capture<'a>(
         v: ContainsLifetime<'a>,
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
     ) -> impl FnOnce() + use<'_> {
         move || _ = v
     }
@@ -200,13 +202,13 @@ mod dyn_trait {
     struct ContainsLifetime<'a>(&'a u8);
 
     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         Box::new(iter::once(v))
     }
 
     fn explicit_bound_path_to_dyn_trait_bound<'a>(
         v: ContainsLifetime<'a>,
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's named elsewhere is confusing
     ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
         Box::new(iter::once(v))
     }
@@ -214,10 +216,28 @@ mod dyn_trait {
 
 /// These tests serve to exercise edge cases of the lint formatting
 mod diagnostic_output {
+    #[derive(Copy, Clone)]
+    struct ContainsLifetime<'a>(&'a u8);
+
+    fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 {
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
+        v.0
+    }
+
     fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
         (v, v)
     }
+
+    fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) {
+        //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing
+        (v.0, v)
+    }
+
+    fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) {
+        //~^ ERROR eliding a lifetime that's named elsewhere is confusing
+        (v, v, ContainsLifetime(v))
+    }
 }
 
 /// Trait functions are represented differently in the HIR. Make sure
@@ -228,20 +248,20 @@ mod trait_functions {
 
     trait TheTrait {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
 
         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     }
 
     impl TheTrait for &u8 {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
             ContainsLifetime(v)
         }
 
         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
-            //~^ ERROR lifetime flowing from input to output with different syntax
+            //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
             ContainsLifetime(self)
         }
     }
@@ -255,7 +275,7 @@ mod foreign_functions {
 
     extern "Rust" {
         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-        //~^ ERROR lifetime flowing from input to output with different syntax
+        //~^ ERROR hiding a lifetime that's elided elsewhere is confusing
     }
 }
 
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
index 108b3f14169..20b7561c594 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
@@ -1,538 +1,613 @@
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:8:47
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:10:47
    |
 LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
-   |                                               ^^        --- the lifetime gets resolved as `'a`
+   |                                               ^^        --- the same lifetime is elided here
    |                                               |
-   |                                               this lifetime flows to the output
+   |                                               the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
 note: the lint level is defined here
   --> $DIR/mismatched-lifetime-syntaxes.rs:1:9
    |
 LL | #![deny(mismatched_lifetime_syntaxes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 {
    |                                                          ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:13:57
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:15:57
    |
 LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
-   |                                                         ^^         -- the lifetime gets resolved as `'a`
+   |                                                         ^^         -- the same lifetime is elided here
    |                                                         |
-   |                                                         this lifetime flows to the output
+   |                                                         the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
 LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:20:48
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:22:48
    |
 LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
-   |                                                ^^^^^^^^^^^^^^^^                      -- the lifetime gets resolved as `'_`
+   |                                                ^^^^^^^^^^^^^^^^                      -- the same lifetime is elided here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is hidden here
    |
-help: one option is to consistently use `'_`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'_`
    |
 LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
    |                                                                ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:25:65
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:27:65
    |
 LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
-   |                                                                 ^^      ---------------- the lifetime gets resolved as `'_`
+   |                                                                 ^^      ---------------- the same lifetime is hidden here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is elided here
    |
-help: one option is to consistently use `'_`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'_`
    |
 LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
    |                                                                                         ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:30:65
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:32:65
    |
 LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
-   |                                                                 ^^      ---------------- the lifetime gets resolved as `'a`
+   |                                                                 ^^      ---------------- the same lifetime is hidden here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> {
    |                                                                                         ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:36:25
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:38:25
    |
 LL |     v: ContainsLifetime<'a>,
-   |                         ^^ this lifetime flows to the output
+   |                         ^^ the lifetime is named here
 LL |
 LL | ) -> ContainsLifetime<'_> {
-   |                       -- the lifetime gets resolved as `'a`
+   |                       -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - ) -> ContainsLifetime<'_> {
 LL + ) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:44:37
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:46:37
    |
 LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-   |                                     ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                     ^^^     ---------------- the same lifetime is hidden here
    |                                     |
-   |                                     this lifetime flows to the output
+   |                                     the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
    |                                                             ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:49:48
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:51:48
    |
 LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-   |                                                ^^        ---------------- the lifetime gets resolved as `'_`
+   |                                                ^^        ---------------- the same lifetime is hidden here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
-   |
-LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
-LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<'_> {
+   |                                                                          ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:54:48
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:56:48
    |
 LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
-   |                                                ^^        ---------------- the lifetime gets resolved as `'a`
+   |                                                ^^        ---------------- the same lifetime is hidden here
    |                                                |
-   |                                                this lifetime flows to the output
+   |                                                the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
    |                                                                          ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:59:58
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:61:58
    |
 LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
-   |                                                          ^^                         -- the lifetime gets resolved as `'a`
+   |                                                          ^^                         -- the same lifetime is elided here
    |                                                          |
-   |                                                          this lifetime flows to the output
+   |                                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
 LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:66:37
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:68:37
    |
 LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
-   |                                     ^^^^^^^^^^^^^^^^     --- the lifetime gets resolved as `'_`
+   |                                     ^^^^^^^^^^^^^^^^     --- the same lifetime is elided here
    |                                     |
-   |                                     this lifetime flows to the output
+   |                                     the lifetime is hidden here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 {
    |                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:71:47
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:73:47
    |
 LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-   |                                               ^^^^^^^^^^^^^^^^      -- the lifetime gets resolved as `'_`
+   |                                               ^^^^^^^^^^^^^^^^      -- the same lifetime is elided here
    |                                               |
-   |                                               this lifetime flows to the output
-   |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   |                                               the lifetime is hidden here
    |
-LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
-LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 {
+   |                                                               ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:76:64
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:78:64
    |
 LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
-   |                                                                ^^      --- the lifetime gets resolved as `'a`
+   |                                                                ^^      --- the same lifetime is elided here
    |                                                                |
-   |                                                                this lifetime flows to the output
+   |                                                                the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
    |                                                                         ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:81:74
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:83:74
    |
 LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
-   |                                                                          ^^       -- the lifetime gets resolved as `'a`
+   |                                                                          ^^       -- the same lifetime is elided here
    |                                                                          |
-   |                                                                          this lifetime flows to the output
+   |                                                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
 LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:87:55
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:89:55
    |
 LL |     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
-   |                                                       ^^          --- the lifetime gets resolved as `'a`
+   |                                                       ^^          --- the same lifetime is elided here
    |                                                       |
-   |                                                       this lifetime flows to the output
+   |                                                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 {
    |                                                                    ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:92:65
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:94:65
    |
 LL |     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
-   |                                                                 ^^           -- the lifetime gets resolved as `'a`
+   |                                                                 ^^           -- the same lifetime is elided here
    |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
 LL +     fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:99:56
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:101:56
    |
 LL |     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-   |                                                        ^^          ---------------- the lifetime gets resolved as `'_`
+   |                                                        ^^          ---------------- the same lifetime is hidden here
    |                                                        |
-   |                                                        this lifetime flows to the output
+   |                                                        the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
-   |
-LL -     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
-LL +     fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
+LL |     fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime<'_> {
+   |                                                                                    ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:104:56
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:106:56
    |
 LL |     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
-   |                                                        ^^          ---------------- the lifetime gets resolved as `'a`
+   |                                                        ^^          ---------------- the same lifetime is hidden here
    |                                                        |
-   |                                                        this lifetime flows to the output
+   |                                                        the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> {
    |                                                                                    ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:109:66
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:111:66
    |
 LL |     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
-   |                                                                  ^^                           -- the lifetime gets resolved as `'a`
+   |                                                                  ^^                           -- the same lifetime is elided here
    |                                                                  |
-   |                                                                  this lifetime flows to the output
+   |                                                                  the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
 LL +     fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:124:39
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:126:39
    |
 LL |     fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
-   |                                       ^^^^^^^        --- the lifetime gets resolved as `'static`
+   |                                       ^^^^^^^        --- the same lifetime is elided here
    |                                       |
-   |                                       this lifetime flows to the output
+   |                                       the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |     fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 {
    |                                                       +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:129:49
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:131:49
    |
 LL |     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
-   |                                                 ^^^^^^^         -- the lifetime gets resolved as `'static`
+   |                                                 ^^^^^^^         -- the same lifetime is elided here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
 LL +     fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:134:40
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:136:40
    |
 LL |     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
-   |                                        ^^^^^^^        ---------------- the lifetime gets resolved as `'static`
+   |                                        ^^^^^^^        ---------------- the same lifetime is hidden here
    |                                        |
-   |                                        this lifetime flows to the output
+   |                                        the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |     fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> {
    |                                                                       +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:139:50
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:141:50
    |
 LL |     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
-   |                                                  ^^^^^^^                         -- the lifetime gets resolved as `'static`
+   |                                                  ^^^^^^^                         -- the same lifetime is elided here
    |                                                  |
-   |                                                  this lifetime flows to the output
+   |                                                  the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
 LL +     fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:145:40
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:147:40
    |
 LL |         fn static_ref_to_implicit_ref(&'static self) -> &u8 {
-   |                                        ^^^^^^^          --- the lifetime gets resolved as `'static`
+   |                                        ^^^^^^^          --- the same lifetime is elided here
    |                                        |
-   |                                        this lifetime flows to the output
+   |                                        the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |         fn static_ref_to_implicit_ref(&'static self) -> &'static u8 {
    |                                                          +++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:150:50
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:152:50
    |
 LL |         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
-   |                                                  ^^^^^^^           -- the lifetime gets resolved as `'static`
+   |                                                  ^^^^^^^           -- the same lifetime is elided here
    |                                                  |
-   |                                                  this lifetime flows to the output
+   |                                                  the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
 LL +         fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:155:41
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:157:41
    |
 LL |         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
-   |                                         ^^^^^^^          ---------------- the lifetime gets resolved as `'static`
+   |                                         ^^^^^^^          ---------------- the same lifetime is hidden here
    |                                         |
-   |                                         this lifetime flows to the output
+   |                                         the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL |         fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> {
    |                                                                          +++++++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:160:51
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:162:51
    |
 LL |         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
-   |                                                   ^^^^^^^                           -- the lifetime gets resolved as `'static`
+   |                                                   ^^^^^^^                           -- the same lifetime is elided here
    |                                                   |
-   |                                                   this lifetime flows to the output
+   |                                                   the lifetime is named here
    |
-help: one option is to consistently use `'static`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'static`
    |
 LL -         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
 LL +         fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:172:55
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:174:55
    |
 LL |     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
-   |                                                       ^^                        -- the lifetime gets resolved as `'a`
+   |                                                       ^^                        -- the same lifetime is elided here
    |                                                       |
-   |                                                       this lifetime flows to the output
+   |                                                       the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
 LL +     fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:177:65
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:179:65
    |
 LL |     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
-   |                                                                 ^^                            -- the lifetime gets resolved as `'a`
-   |                                                                 |
-   |                                                                 this lifetime flows to the output
+   |                                                                 ^^ the lifetime is named here -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
 LL +     fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:182:72
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:184:72
    |
 LL |     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
-   |                                                                        ^^                      -- the lifetime gets resolved as `'a`
+   |                                                                        ^^                      -- the same lifetime is elided here
    |                                                                        |
-   |                                                                        this lifetime flows to the output
+   |                                                                        the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
 LL +     fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:188:29
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:190:29
    |
 LL |         v: ContainsLifetime<'a>,
-   |                             ^^ this lifetime flows to the output
+   |                             ^^ the lifetime is named here
 LL |
 LL |     ) -> impl FnOnce() + use<'_> {
-   |                              -- the lifetime gets resolved as `'a`
+   |                              -- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL -     ) -> impl FnOnce() + use<'_> {
 LL +     ) -> impl FnOnce() + use<'a> {
    |
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:202:54
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:204:54
    |
 LL |     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
-   |                                                      ^^                                ---    -- the lifetimes get resolved as `'a`
-   |                                                      |                                 |
-   |                                                      |                                 the lifetimes get resolved as `'a`
-   |                                                      this lifetime flows to the output
+   |                                                      ^^ the lifetime is named here     --- the same lifetime is elided here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &'a u8> + '_> {
    |                                                                                         ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:208:29
+error: hiding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:210:29
    |
 LL |         v: ContainsLifetime<'a>,
-   |                             ^^ this lifetime flows to the output
+   |                             ^^ the lifetime is named here
 LL |
 LL |     ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
-   |                                  ----------------    -- the lifetimes get resolved as `'a`
-   |                                  |
-   |                                  the lifetimes get resolved as `'a`
+   |                                  ---------------- the same lifetime is hidden here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     ) -> Box<dyn Iterator<Item = ContainsLifetime<'a>> + '_> {
    |                                                  ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:217:33
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:222:33
+   |
+LL |     fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 {
+   |                                 ^^      ^^         --- the same lifetime is elided here
+   |                                 |       |
+   |                                 |       the lifetime is named here
+   |                                 the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 {
+   |                                                     ++
+
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:227:33
    |
 LL |     fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
-   |                                 ^^         ---  --- the lifetimes get resolved as `'a`
+   |                                 ^^         ---  --- the same lifetime is elided here
    |                                 |          |
-   |                                 |          the lifetimes get resolved as `'a`
-   |                                 this lifetime flows to the output
+   |                                 |          the same lifetime is elided here
+   |                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) {
    |                                             ++      ++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:230:45
+error: hiding or eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:232:53
+   |
+LL |     fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) {
+   |                                                     ^^       ---  ---------------- the same lifetime is hidden here
+   |                                                     |        |
+   |                                                     |        the same lifetime is elided here
+   |                                                     the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, ContainsLifetime<'a>) {
+   |                                                               ++                     ++++
+
+error: eliding a lifetime that's named elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:237:38
+   |
+LL |     fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) {
+   |                                      ^^         ---   --                      -- the same lifetime is named here
+   |                                      |          |     |
+   |                                      |          |     the same lifetime is named here
+   |                                      |          the same lifetime is elided here
+   |                                      the lifetime is named here
+   |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
+   |
+LL |     fn explicit_bound_output<'a>(v: &'a u8) -> (&'a u8, &'a u8, ContainsLifetime<'a>) {
+   |                                                  ++
+
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:250:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>;
    |                                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:233:49
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:253:49
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
-   |                                                 ^^^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                                 ^^^^^     ---------------- the same lifetime is hidden here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>;
    |                                                                           ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:238:45
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:258:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
    |                                                                     ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:243:49
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:263:49
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
-   |                                                 ^^^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                                 ^^^^^     ---------------- the same lifetime is hidden here
    |                                                 |
-   |                                                 this lifetime flows to the output
+   |                                                 the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
    |                                                                           ++++
 
-error: lifetime flowing from input to output with different syntax can be confusing
-  --> $DIR/mismatched-lifetime-syntaxes.rs:257:45
+error: hiding a lifetime that's elided elsewhere is confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:277:45
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
-   |                                             ^^^     ---------------- the lifetime gets resolved as `'_`
+   |                                             ^^^     ---------------- the same lifetime is hidden here
    |                                             |
-   |                                             this lifetime flows to the output
+   |                                             the lifetime is elided here
    |
-help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: use `'_` for type paths
    |
 LL |         fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>;
    |                                                                     ++++
 
-error: aborting due to 39 previous errors
+error: aborting due to 42 previous errors
 
diff --git a/tests/ui/linking/export-executable-symbols.rs b/tests/ui/linking/export-executable-symbols.rs
index aea5527b6a1..2bff58ca38a 100644
--- a/tests/ui/linking/export-executable-symbols.rs
+++ b/tests/ui/linking/export-executable-symbols.rs
@@ -1,22 +1,22 @@
 //@ run-pass
-//@ only-linux
-//@ only-gnu
-//@ compile-flags: -Zexport-executable-symbols
+//@ compile-flags: -Ctarget-feature=-crt-static -Zexport-executable-symbols
+//@ ignore-wasm
+//@ ignore-cross-compile
 //@ edition: 2024
 
 // Regression test for <https://github.com/rust-lang/rust/issues/101610>.
 
 #![feature(rustc_private)]
 
-extern crate libc;
-
 #[unsafe(no_mangle)]
 fn hack() -> u64 {
     998244353
 }
 
 fn main() {
+    #[cfg(unix)]
     unsafe {
+        extern crate libc;
         let handle = libc::dlopen(std::ptr::null(), libc::RTLD_NOW);
         let ptr = libc::dlsym(handle, c"hack".as_ptr());
         let ptr: Option<unsafe fn() -> u64> = std::mem::transmute(ptr);
@@ -27,4 +27,24 @@ fn main() {
             panic!("symbol `hack` is not found");
         }
     }
+    #[cfg(windows)]
+    unsafe {
+        type PCSTR = *const u8;
+        type HMODULE = *mut core::ffi::c_void;
+        type FARPROC = Option<unsafe extern "system" fn() -> isize>;
+        #[link(name = "kernel32", kind = "raw-dylib")]
+        unsafe extern "system" {
+            fn GetModuleHandleA(lpmodulename: PCSTR) -> HMODULE;
+            fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
+        }
+        let handle = GetModuleHandleA(std::ptr::null_mut());
+        let ptr = GetProcAddress(handle, b"hack\0".as_ptr());
+        let ptr: Option<unsafe fn() -> u64> = std::mem::transmute(ptr);
+        if let Some(f) = ptr {
+            assert!(f() == 998244353);
+            println!("symbol `hack` is found successfully");
+        } else {
+            panic!("symbol `hack` is not found");
+        }
+    }
 }
diff --git a/tests/ui/darwin-ld64.rs b/tests/ui/linking/ld64-cross-compilation.rs
index 75acc07a002..d6c6d1ff91d 100644
--- a/tests/ui/darwin-ld64.rs
+++ b/tests/ui/linking/ld64-cross-compilation.rs
@@ -1,11 +1,11 @@
+//! This is a regression test for https://github.com/rust-lang/rust/issues/140686.
+//! Although this is a ld64(ld-classic) bug, we still need to support it
+//! due to cross-compilation and support for older Xcode.
+
 //@ compile-flags: -Copt-level=3 -Ccodegen-units=256 -Clink-arg=-ld_classic
 //@ run-pass
 //@ only-x86_64-apple-darwin
 
-// This is a regression test for https://github.com/rust-lang/rust/issues/140686.
-// Although this is a ld64(ld-classic) bug, we still need to support it
-// due to cross-compilation and support for older Xcode.
-
 fn main() {
     let dst: Vec<u8> = Vec::new();
     let len = broken_func(std::hint::black_box(2), dst);
diff --git a/tests/ui/lint/invalid_null_args.rs b/tests/ui/lint/invalid_null_args.rs
index f40f06a0d36..ee29d622ad7 100644
--- a/tests/ui/lint/invalid_null_args.rs
+++ b/tests/ui/lint/invalid_null_args.rs
@@ -58,10 +58,9 @@ unsafe fn null_ptr() {
     let _a: A = ptr::read_unaligned(ptr::null_mut());
     //~^ ERROR calling this function with a null pointer is undefined behavior
 
+    // These two should *not* fire the lint.
     let _a: A = ptr::read_volatile(ptr::null());
-    //~^ ERROR calling this function with a null pointer is undefined behavior
     let _a: A = ptr::read_volatile(ptr::null_mut());
-    //~^ ERROR calling this function with a null pointer is undefined behavior
 
     let _a: A = ptr::replace(ptr::null_mut(), v);
     //~^ ERROR calling this function with a null pointer is undefined behavior
@@ -82,8 +81,8 @@ unsafe fn null_ptr() {
     ptr::write_unaligned(ptr::null_mut(), v);
     //~^ ERROR calling this function with a null pointer is undefined behavior
 
+    // This one should *not* fire the lint.
     ptr::write_volatile(ptr::null_mut(), v);
-    //~^ ERROR calling this function with a null pointer is undefined behavior
 
     ptr::write_bytes::<usize>(ptr::null_mut(), 42, 0);
     //~^ ERROR calling this function with a null pointer is undefined behavior
diff --git a/tests/ui/lint/invalid_null_args.stderr b/tests/ui/lint/invalid_null_args.stderr
index 11c6270cfb7..028bd7051dc 100644
--- a/tests/ui/lint/invalid_null_args.stderr
+++ b/tests/ui/lint/invalid_null_args.stderr
@@ -164,27 +164,7 @@ LL |     let _a: A = ptr::read_unaligned(ptr::null_mut());
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:61:17
-   |
-LL |     let _a: A = ptr::read_volatile(ptr::null());
-   |                 ^^^^^^^^^^^^^^^^^^^-----------^
-   |                                    |
-   |                                    null pointer originates from here
-   |
-   = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
-
-error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:63:17
-   |
-LL |     let _a: A = ptr::read_volatile(ptr::null_mut());
-   |                 ^^^^^^^^^^^^^^^^^^^---------------^
-   |                                    |
-   |                                    null pointer originates from here
-   |
-   = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
-
-error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:66:17
+  --> $DIR/invalid_null_args.rs:65:17
    |
 LL |     let _a: A = ptr::replace(ptr::null_mut(), v);
    |                 ^^^^^^^^^^^^^---------------^^^^
@@ -194,7 +174,7 @@ LL |     let _a: A = ptr::replace(ptr::null_mut(), v);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:69:5
+  --> $DIR/invalid_null_args.rs:68:5
    |
 LL |     ptr::swap::<A>(ptr::null_mut(), &mut v);
    |     ^^^^^^^^^^^^^^^---------------^^^^^^^^^
@@ -204,7 +184,7 @@ LL |     ptr::swap::<A>(ptr::null_mut(), &mut v);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:71:5
+  --> $DIR/invalid_null_args.rs:70:5
    |
 LL |     ptr::swap::<A>(&mut v, ptr::null_mut());
    |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
@@ -214,7 +194,7 @@ LL |     ptr::swap::<A>(&mut v, ptr::null_mut());
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:74:5
+  --> $DIR/invalid_null_args.rs:73:5
    |
 LL |     ptr::swap_nonoverlapping::<A>(ptr::null_mut(), &mut v, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^^^^^
@@ -224,7 +204,7 @@ LL |     ptr::swap_nonoverlapping::<A>(ptr::null_mut(), &mut v, 0);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:76:5
+  --> $DIR/invalid_null_args.rs:75:5
    |
 LL |     ptr::swap_nonoverlapping::<A>(&mut v, ptr::null_mut(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@@ -234,7 +214,7 @@ LL |     ptr::swap_nonoverlapping::<A>(&mut v, ptr::null_mut(), 0);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:79:5
+  --> $DIR/invalid_null_args.rs:78:5
    |
 LL |     ptr::write(ptr::null_mut(), v);
    |     ^^^^^^^^^^^---------------^^^^
@@ -244,7 +224,7 @@ LL |     ptr::write(ptr::null_mut(), v);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:82:5
+  --> $DIR/invalid_null_args.rs:81:5
    |
 LL |     ptr::write_unaligned(ptr::null_mut(), v);
    |     ^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@@ -254,17 +234,7 @@ LL |     ptr::write_unaligned(ptr::null_mut(), v);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:85:5
-   |
-LL |     ptr::write_volatile(ptr::null_mut(), v);
-   |     ^^^^^^^^^^^^^^^^^^^^---------------^^^^
-   |                         |
-   |                         null pointer originates from here
-   |
-   = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
-
-error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:88:5
+  --> $DIR/invalid_null_args.rs:87:5
    |
 LL |     ptr::write_bytes::<usize>(ptr::null_mut(), 42, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^^^^^
@@ -274,7 +244,7 @@ LL |     ptr::write_bytes::<usize>(ptr::null_mut(), 42, 0);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:93:18
+  --> $DIR/invalid_null_args.rs:92:18
    |
 LL |     let _a: u8 = ptr::read(const_ptr);
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -287,7 +257,7 @@ LL |     let null_ptr = ptr::null_mut();
    |                    ^^^^^^^^^^^^^^^
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:100:5
+  --> $DIR/invalid_null_args.rs:99:5
    |
 LL |     std::slice::from_raw_parts::<()>(ptr::null(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -297,7 +267,7 @@ LL |     std::slice::from_raw_parts::<()>(ptr::null(), 0);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:102:5
+  --> $DIR/invalid_null_args.rs:101:5
    |
 LL |     std::slice::from_raw_parts::<Zst>(ptr::null(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
@@ -307,7 +277,7 @@ LL |     std::slice::from_raw_parts::<Zst>(ptr::null(), 0);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:104:5
+  --> $DIR/invalid_null_args.rs:103:5
    |
 LL |     std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@@ -317,7 +287,7 @@ LL |     std::slice::from_raw_parts_mut::<()>(ptr::null_mut(), 0);
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
 error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused
-  --> $DIR/invalid_null_args.rs:106:5
+  --> $DIR/invalid_null_args.rs:105:5
    |
 LL |     std::slice::from_raw_parts_mut::<Zst>(ptr::null_mut(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
@@ -326,5 +296,5 @@ LL |     std::slice::from_raw_parts_mut::<Zst>(ptr::null_mut(), 0);
    |
    = help: for more information, visit <https://doc.rust-lang.org/std/ptr/index.html> and <https://doc.rust-lang.org/reference/behavior-considered-undefined.html>
 
-error: aborting due to 31 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/tests/ui/lint/lint-double-negations-macro.rs b/tests/ui/lint/lint-double-negations-macro.rs
new file mode 100644
index 00000000000..a6583271d5a
--- /dev/null
+++ b/tests/ui/lint/lint-double-negations-macro.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+macro_rules! neg {
+    ($e: expr) => {
+        -$e
+    };
+}
+macro_rules! bad_macro {
+    ($e: expr) => {
+        --$e //~ WARN use of a double negation
+    };
+}
+
+fn main() {
+    neg!(-1);
+    bad_macro!(1);
+}
diff --git a/tests/ui/lint/lint-double-negations-macro.stderr b/tests/ui/lint/lint-double-negations-macro.stderr
new file mode 100644
index 00000000000..d6ac9be48f3
--- /dev/null
+++ b/tests/ui/lint/lint-double-negations-macro.stderr
@@ -0,0 +1,20 @@
+warning: use of a double negation
+  --> $DIR/lint-double-negations-macro.rs:9:9
+   |
+LL |         --$e
+   |         ^^^^
+...
+LL |     bad_macro!(1);
+   |     ------------- in this macro invocation
+   |
+   = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
+   = note: use `-= 1` if you meant to decrement the value
+   = note: `#[warn(double_negations)]` on by default
+   = note: this warning originates in the macro `bad_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add parentheses for clarity
+   |
+LL |         -(-$e)
+   |          +   +
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/lint-stability-deprecated.stderr b/tests/ui/lint/lint-stability-deprecated.stderr
index 51205ff4340..0399fab746e 100644
--- a/tests/ui/lint/lint-stability-deprecated.stderr
+++ b/tests/ui/lint/lint-stability-deprecated.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated function `lint_stability::deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:24:9
+warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text
+  --> $DIR/lint-stability-deprecated.rs:97:48
    |
-LL |         deprecated();
-   |         ^^^^^^^^^^
+LL |         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
+   |                                                ^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/lint-stability-deprecated.rs:6:9
@@ -10,6 +10,12 @@ note: the lint level is defined here
 LL | #![warn(deprecated)]
    |         ^^^^^^^^^^
 
+warning: use of deprecated function `lint_stability::deprecated`: text
+  --> $DIR/lint-stability-deprecated.rs:24:9
+   |
+LL |         deprecated();
+   |         ^^^^^^^^^^
+
 warning: use of deprecated method `lint_stability::Trait::trait_deprecated`: text
   --> $DIR/lint-stability-deprecated.rs:29:16
    |
@@ -317,12 +323,6 @@ LL |             fn_in_body();
    |             ^^^^^^^^^^
 
 warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:97:48
-   |
-LL |         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
-   |                                                ^^^^^^^^^^^^^^^^^
-
-warning: use of deprecated associated type `lint_stability::TraitWithAssociatedTypes::TypeDeprecated`: text
   --> $DIR/lint-stability-deprecated.rs:101:13
    |
 LL |             TypeDeprecated = u16,
diff --git a/tests/ui/lint/lint-stability.stderr b/tests/ui/lint/lint-stability.stderr
index fd57908a77b..249f3ccaa54 100644
--- a/tests/ui/lint/lint-stability.stderr
+++ b/tests/ui/lint/lint-stability.stderr
@@ -1,4 +1,13 @@
 error[E0658]: use of unstable library feature `unstable_test_feature`
+  --> $DIR/lint-stability.rs:88:48
+   |
+LL |         struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
+   |                                                ^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable_test_feature)]` 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]: use of unstable library feature `unstable_test_feature`
   --> $DIR/lint-stability.rs:17:5
    |
 LL |     extern crate stability_cfg2;
@@ -368,15 +377,6 @@ LL |         let _ = Unstable::StableVariant;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `unstable_test_feature`
-  --> $DIR/lint-stability.rs:88:48
-   |
-LL |         struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
-   |                                                ^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable_test_feature)]` 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]: use of unstable library feature `unstable_test_feature`
   --> $DIR/lint-stability.rs:92:13
    |
 LL |             TypeUnstable = u8,
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs
index bf94a42f6e0..cfa6c2b4228 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.rs
+++ b/tests/ui/lint/unused/unused-attr-duplicate.rs
@@ -66,9 +66,11 @@ fn t1() {}
 #[non_exhaustive] //~ ERROR unused attribute
 pub struct X;
 
+trait Trait {}
+
 #[automatically_derived]
 #[automatically_derived] //~ ERROR unused attribute
-impl X {}
+impl Trait for X {}
 
 #[inline(always)]
 #[inline(never)] //~ ERROR unused attribute
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index 6db6af823f4..ecc1b7ff5a4 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -179,112 +179,112 @@ LL | #[non_exhaustive]
    | ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:70:1
+  --> $DIR/unused-attr-duplicate.rs:72:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:69:1
+  --> $DIR/unused-attr-duplicate.rs:71:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:74:1
+  --> $DIR/unused-attr-duplicate.rs:76:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:73:1
+  --> $DIR/unused-attr-duplicate.rs:75:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:77:1
+  --> $DIR/unused-attr-duplicate.rs:79:1
    |
 LL | #[cold]
    | ^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:76:1
+  --> $DIR/unused-attr-duplicate.rs:78:1
    |
 LL | #[cold]
    | ^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:79:1
+  --> $DIR/unused-attr-duplicate.rs:81:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:78:1
+  --> $DIR/unused-attr-duplicate.rs:80:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:86:5
+  --> $DIR/unused-attr-duplicate.rs:88:5
    |
 LL |     #[link_name = "this_does_not_exist"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:88:5
+  --> $DIR/unused-attr-duplicate.rs:90:5
    |
 LL |     #[link_name = "rust_dbg_extern_identity_u32"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:92:1
+  --> $DIR/unused-attr-duplicate.rs:94:1
    |
 LL | #[export_name = "exported_symbol_name"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:94:1
+  --> $DIR/unused-attr-duplicate.rs:96:1
    |
 LL | #[export_name = "exported_symbol_name2"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:98:1
+  --> $DIR/unused-attr-duplicate.rs:100:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:97:1
+  --> $DIR/unused-attr-duplicate.rs:99:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:102:1
+  --> $DIR/unused-attr-duplicate.rs:104:1
    |
 LL | #[used]
    | ^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:101:1
+  --> $DIR/unused-attr-duplicate.rs:103:1
    |
 LL | #[used]
    | ^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:105:1
+  --> $DIR/unused-attr-duplicate.rs:107:1
    |
 LL | #[link_section = ".text"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:108:1
+  --> $DIR/unused-attr-duplicate.rs:110:1
    |
 LL | #[link_section = ".bss"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr
index 28fd8eeb8cb..862ffa42d80 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.stderr
+++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr
@@ -45,7 +45,7 @@ error: `#[must_use]` has no effect when applied to a static item
 LL | #[must_use]
    | ^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to an implementation block
+error: `#[must_use]` has no effect when applied to an inherent implementation block
   --> $DIR/unused_attributes-must_use.rs:33:1
    |
 LL | #[must_use]
@@ -69,7 +69,7 @@ error: `#[must_use]` has no effect when applied to a type parameter
 LL | fn qux<#[must_use] T>(_: T) {}
    |        ^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to an implementation block
+error: `#[must_use]` has no effect when applied to an trait implementation block
   --> $DIR/unused_attributes-must_use.rs:79:1
    |
 LL | #[must_use]
diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs
index 89043275329..d6855f8760d 100644
--- a/tests/ui/lto/debuginfo-lto-alloc.rs
+++ b/tests/ui/lto/debuginfo-lto-alloc.rs
@@ -8,8 +8,9 @@
 // This test reproduces the circumstances that caused the error to appear, and checks
 // that compilation is successful.
 
-//@ check-pass
+//@ build-pass
 //@ compile-flags: --test -C debuginfo=2 -C lto=fat
+//@ no-prefer-dynamic
 //@ incremental
 
 extern crate alloc;
diff --git a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
index 32cff62284e..aeecb82e9d9 100644
--- a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
+++ b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
@@ -20,17 +20,12 @@ error[E0034]: multiple applicable items in scope
 LL |     let z = x.foo();
    |               ^^^ multiple `foo` found
    |
-note: candidate #1 is defined in the trait `FinalFoo`
-  --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:60:5
-   |
-LL |     fn foo(&self) -> u8;
-   |     ^^^^^^^^^^^^^^^^^^^^
-note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T`
+note: candidate #1 is defined in an impl of the trait `NuisanceFoo` for the type `T`
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:73:9
    |
 LL |         fn foo(self) {}
    |         ^^^^^^^^^^^^
-note: candidate #3 is defined in an impl of the trait `X` for the type `T`
+note: candidate #2 is defined in an impl of the trait `X` for the type `T`
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:46:9
    |
 LL |         fn foo(self: Smaht<Self, u64>) -> u64 {
@@ -38,14 +33,9 @@ LL |         fn foo(self: Smaht<Self, u64>) -> u64 {
 help: disambiguate the method for candidate #1
    |
 LL -     let z = x.foo();
-LL +     let z = FinalFoo::foo(&x);
-   |
-help: disambiguate the method for candidate #2
-   |
-LL -     let z = x.foo();
 LL +     let z = NuisanceFoo::foo(x);
    |
-help: disambiguate the method for candidate #3
+help: disambiguate the method for candidate #2
    |
 LL -     let z = x.foo();
 LL +     let z = X::foo(x);
diff --git a/tests/ui/methods/wrong-ambig-message.rs b/tests/ui/methods/wrong-ambig-message.rs
new file mode 100644
index 00000000000..f88d77e259d
--- /dev/null
+++ b/tests/ui/methods/wrong-ambig-message.rs
@@ -0,0 +1,34 @@
+fn main() {
+    trait Hello {
+        fn name(&self) -> String;
+    }
+
+    #[derive(Debug)]
+    struct Container2 {
+        val: String,
+    }
+
+    trait AName2 {
+        fn name(&self) -> String;
+    }
+
+    trait BName2 {
+        fn name(&self, v: bool) -> String;
+    }
+
+    impl AName2 for Container2 {
+        fn name(&self) -> String {
+            "aname2".into()
+        }
+    }
+
+    impl BName2 for Container2 {
+        fn name(&self, _v: bool) -> String {
+            "bname2".into()
+        }
+    }
+
+    let c2 = Container2 { val: "abc".into() };
+    println!("c2 = {:?}", c2.name());
+    //~^ ERROR: multiple applicable items in scope
+}
diff --git a/tests/ui/methods/wrong-ambig-message.stderr b/tests/ui/methods/wrong-ambig-message.stderr
new file mode 100644
index 00000000000..9a254595e40
--- /dev/null
+++ b/tests/ui/methods/wrong-ambig-message.stderr
@@ -0,0 +1,30 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/wrong-ambig-message.rs:32:30
+   |
+LL |     println!("c2 = {:?}", c2.name());
+   |                              ^^^^ multiple `name` found
+   |
+note: candidate #1 is defined in an impl of the trait `AName2` for the type `Container2`
+  --> $DIR/wrong-ambig-message.rs:20:9
+   |
+LL |         fn name(&self) -> String {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in an impl of the trait `BName2` for the type `Container2`
+  --> $DIR/wrong-ambig-message.rs:26:9
+   |
+LL |         fn name(&self, _v: bool) -> String {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method for candidate #1
+   |
+LL -     println!("c2 = {:?}", c2.name());
+LL +     println!("c2 = {:?}", AName2::name(&c2));
+   |
+help: disambiguate the method for candidate #2
+   |
+LL -     println!("c2 = {:?}", c2.name());
+LL +     println!("c2 = {:?}", BName2::name(&c2));
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0034`.
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/crashes/128094.rs b/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs
index 56d09d78bed..f0d174cd01b 100644
--- a/tests/crashes/128094.rs
+++ b/tests/ui/mir/gvn-nonsensical-coroutine-layout.rs
@@ -1,15 +1,19 @@
-//@ known-bug: rust-lang/rust#128094
+//! Verify that we do not ICE when a coroutine body is malformed.
 //@ compile-flags: -Zmir-enable-passes=+GVN
 //@ edition: 2018
 
 pub enum Request {
     TestSome(T),
+    //~^ ERROR cannot find type `T` in this scope [E0412]
 }
 
 pub async fn handle_event(event: Request) {
     async move {
         static instance: Request = Request { bar: 17 };
+        //~^ ERROR expected struct, variant or union type, found enum `Request` [E0574]
         &instance
     }
     .await;
 }
+
+fn main() {}
diff --git a/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr b/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr
new file mode 100644
index 00000000000..abc7b16ca74
--- /dev/null
+++ b/tests/ui/mir/gvn-nonsensical-coroutine-layout.stderr
@@ -0,0 +1,26 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/gvn-nonsensical-coroutine-layout.rs:6:14
+   |
+LL |     TestSome(T),
+   |              ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | pub enum Request<T> {
+   |                 +++
+
+error[E0574]: expected struct, variant or union type, found enum `Request`
+  --> $DIR/gvn-nonsensical-coroutine-layout.rs:12:36
+   |
+LL |         static instance: Request = Request { bar: 17 };
+   |                                    ^^^^^^^ not a struct, variant or union type
+   |
+help: consider importing this struct instead
+   |
+LL + use std::error::Request;
+   |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0412, E0574.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/crashes/135128.rs b/tests/ui/mir/gvn-nonsensical-sized-str.rs
index c718b758dc6..29a82f8ce2a 100644
--- a/tests/crashes/135128.rs
+++ b/tests/ui/mir/gvn-nonsensical-sized-str.rs
@@ -1,13 +1,16 @@
-//@ known-bug: #135128
+//! Verify that we do not ICE when optimizing bodies with nonsensical bounds.
 //@ compile-flags: -Copt-level=1
 //@ edition: 2021
+//@ build-pass
 
 #![feature(trivial_bounds)]
 
 async fn return_str() -> str
 where
     str: Sized,
+    //~^ WARN trait bound str: Sized does not depend on any type or lifetime parameters
 {
     *"Sized".to_string().into_boxed_str()
 }
+
 fn main() {}
diff --git a/tests/ui/mir/gvn-nonsensical-sized-str.stderr b/tests/ui/mir/gvn-nonsensical-sized-str.stderr
new file mode 100644
index 00000000000..08f0193e9f6
--- /dev/null
+++ b/tests/ui/mir/gvn-nonsensical-sized-str.stderr
@@ -0,0 +1,10 @@
+warning: trait bound str: Sized does not depend on any type or lifetime parameters
+  --> $DIR/gvn-nonsensical-sized-str.rs:10:10
+   |
+LL |     str: Sized,
+   |          ^^^^^
+   |
+   = note: `#[warn(trivial_bounds)]` on by default
+
+warning: 1 warning emitted
+
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/mir/validate/critical-edge.rs b/tests/ui/mir/validate/critical-edge.rs
index 2a3bf6a6181..7fe3891d642 100644
--- a/tests/ui/mir/validate/critical-edge.rs
+++ b/tests/ui/mir/validate/critical-edge.rs
@@ -21,6 +21,8 @@ pub fn f(a: u32) -> u32 {
         }
         bb1 = {
             Call(RET = f(1), ReturnTo(bb2), UnwindTerminate(ReasonAbi))
+//~^ ERROR broken MIR in Item
+//~| ERROR encountered critical edge in `Call` terminator
         }
 
         bb2 = {
@@ -29,5 +31,3 @@ pub fn f(a: u32) -> u32 {
         }
     }
 }
-
-//~? RAW encountered critical edge in `Call` terminator
diff --git a/tests/ui/missing/missing-stability.stderr b/tests/ui/missing/missing-stability.stderr
index 659f8c78cae..bf8046c4e12 100644
--- a/tests/ui/missing/missing-stability.stderr
+++ b/tests/ui/missing/missing-stability.stderr
@@ -1,17 +1,14 @@
 error: function has missing stability attribute
   --> $DIR/missing-stability.rs:8:1
    |
-LL | / pub fn unmarked() {
-LL | |
-LL | |     ()
-LL | | }
-   | |_^
+LL | pub fn unmarked() {
+   | ^^^^^^^^^^^^^^^^^
 
 error: function has missing stability attribute
   --> $DIR/missing-stability.rs:22:5
    |
 LL |     pub fn unmarked() {}
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/issue-50716.rs b/tests/ui/nll/issue-50716.rs
index 76c6fc5e7b9..96168ebeaa1 100644
--- a/tests/ui/nll/issue-50716.rs
+++ b/tests/ui/nll/issue-50716.rs
@@ -5,7 +5,7 @@ trait A {
     type X: ?Sized;
 }
 
-fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) //~ ERROR
+fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
 where
     for<'b> &'b T: A,
     <&'static T as A>::X: Sized
diff --git a/tests/ui/nll/issue-50716.stderr b/tests/ui/nll/issue-50716.stderr
index edd7fd765da..536f88085de 100644
--- a/tests/ui/nll/issue-50716.stderr
+++ b/tests/ui/nll/issue-50716.stderr
@@ -1,18 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-50716.rs:8:27
-   |
-LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
-   |                           ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected trait `<<&'a T as A>::X as MetaSized>`
-              found trait `<<&'static T as A>::X as MetaSized>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/issue-50716.rs:8:8
-   |
-LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
-   |        ^^
-   = note: ...does not necessarily outlive the static lifetime
-
 error: lifetime may not live long enough
   --> $DIR/issue-50716.rs:13:14
    |
@@ -22,6 +7,5 @@ LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
 LL |     let _x = *s;
    |              ^^ proving this value is `Sized` requires that `'a` must outlive `'static`
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
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 3876dbb37c3..2009f69e19e 100644
--- a/tests/ui/panics/panic-main.rs
+++ b/tests/ui/panics/panic-main.rs
@@ -1,4 +1,37 @@
-//@ run-fail
+//@ 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
+
 //@ 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..33350dfbc4f 100644
--- a/tests/ui/precondition-checks/read_volatile.rs
+++ b/tests/ui/precondition-checks/read_volatile.rs
@@ -1,9 +1,7 @@
-//@ 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
-
-#![allow(invalid_null_arguments)]
+//@ revisions: misaligned
 
 use std::ptr;
 
@@ -11,8 +9,6 @@ fn main() {
     let src = [0u16; 2];
     let src = src.as_ptr();
     unsafe {
-        #[cfg(null)]
-        ptr::read_volatile(ptr::null::<u8>());
         #[cfg(misaligned)]
         ptr::read_volatile(src.byte_add(1));
     }
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..d6ad6320e41 100644
--- a/tests/ui/precondition-checks/write_volatile.rs
+++ b/tests/ui/precondition-checks/write_volatile.rs
@@ -1,9 +1,7 @@
-//@ 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
-
-#![allow(invalid_null_arguments)]
+//@ revisions: misaligned
 
 use std::ptr;
 
@@ -11,8 +9,6 @@ fn main() {
     let mut dst = [0u16; 2];
     let mut dst = dst.as_mut_ptr();
     unsafe {
-        #[cfg(null)]
-        ptr::write_volatile(ptr::null_mut::<u8>(), 1u8);
         #[cfg(misaligned)]
         ptr::write_volatile(dst.byte_add(1), 1u16);
     }
diff --git a/tests/ui/privacy/effective_visibilities_invariants.stderr b/tests/ui/privacy/effective_visibilities_invariants.stderr
index 64d0402f84e..97bee1e2d8d 100644
--- a/tests/ui/privacy/effective_visibilities_invariants.stderr
+++ b/tests/ui/privacy/effective_visibilities_invariants.stderr
@@ -23,7 +23,7 @@ error: module has missing stability attribute
   --> $DIR/effective_visibilities_invariants.rs:5:1
    |
 LL | pub mod m {}
-   | ^^^^^^^^^^^^
+   | ^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/privacy/issue-113860-1.stderr b/tests/ui/privacy/issue-113860-1.stderr
index dad9ebadf04..764c9f4925b 100644
--- a/tests/ui/privacy/issue-113860-1.stderr
+++ b/tests/ui/privacy/issue-113860-1.stderr
@@ -20,28 +20,20 @@ LL | | fn main() {}
 error: trait has missing stability attribute
   --> $DIR/issue-113860-1.rs:4:1
    |
-LL | / pub trait Trait {
-LL | |
-LL | |     fn fun() {}
-LL | |
-LL | | }
-   | |_^
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^
 
 error: implementation has missing stability attribute
   --> $DIR/issue-113860-1.rs:10:1
    |
-LL | / impl Trait for u8 {
-LL | |
-LL | |     pub(self) fn fun() {}
-LL | |
-LL | | }
-   | |_^
+LL | impl Trait for u8 {
+   | ^^^^^^^^^^^^^^^^^
 
 error: associated function has missing stability attribute
   --> $DIR/issue-113860-1.rs:6:5
    |
 LL |     fn fun() {}
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/privacy/issue-113860-2.stderr b/tests/ui/privacy/issue-113860-2.stderr
index 9805c22dbdf..d0847aa2b49 100644
--- a/tests/ui/privacy/issue-113860-2.stderr
+++ b/tests/ui/privacy/issue-113860-2.stderr
@@ -20,28 +20,20 @@ LL | | fn main() {}
 error: trait has missing stability attribute
   --> $DIR/issue-113860-2.rs:4:1
    |
-LL | / pub trait Trait {
-LL | |
-LL | |     type X;
-LL | |
-LL | | }
-   | |_^
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^
 
 error: implementation has missing stability attribute
   --> $DIR/issue-113860-2.rs:10:1
    |
-LL | / impl Trait for u8 {
-LL | |
-LL | |     pub(self) type X = Self;
-LL | |
-LL | | }
-   | |_^
+LL | impl Trait for u8 {
+   | ^^^^^^^^^^^^^^^^^
 
 error: associated type has missing stability attribute
   --> $DIR/issue-113860-2.rs:6:5
    |
 LL |     type X;
-   |     ^^^^^^^
+   |     ^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/privacy/issue-113860.stderr b/tests/ui/privacy/issue-113860.stderr
index 88efcae4a85..d7a15255b15 100644
--- a/tests/ui/privacy/issue-113860.stderr
+++ b/tests/ui/privacy/issue-113860.stderr
@@ -20,28 +20,20 @@ LL | | fn main() {}
 error: trait has missing stability attribute
   --> $DIR/issue-113860.rs:4:1
    |
-LL | / pub trait Trait {
-LL | |
-LL | |     const X: u32;
-LL | |
-LL | | }
-   | |_^
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^
 
 error: implementation has missing stability attribute
   --> $DIR/issue-113860.rs:10:1
    |
-LL | / impl Trait for u8 {
-LL | |
-LL | |     pub(self) const X: u32 = 3;
-LL | |
-LL | | }
-   | |_^
+LL | impl Trait for u8 {
+   | ^^^^^^^^^^^^^^^^^
 
 error: associated constant has missing stability attribute
   --> $DIR/issue-113860.rs:6:5
    |
 LL |     const X: u32;
-   |     ^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/privacy/private-in-public-warn.rs b/tests/ui/privacy/private-in-public-warn.rs
index 746b98fbd07..f79e4641312 100644
--- a/tests/ui/privacy/private-in-public-warn.rs
+++ b/tests/ui/privacy/private-in-public-warn.rs
@@ -35,6 +35,7 @@ mod types {
 
 mod traits {
     trait PrivTr {}
+    impl PrivTr for () {}
     pub struct Pub<T>(T);
     pub trait PubTr {}
 
@@ -45,7 +46,10 @@ mod traits {
     pub trait Tr3 {
         type Alias: PrivTr;
         //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::Alias`
-        fn f<T: PrivTr>(arg: T) {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f`
+        fn f<T: PrivTr>(arg: T) {}
+        //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f`
+        fn g() -> impl PrivTr;
+        fn h() -> impl PrivTr {}
     }
     impl<T: PrivTr> Pub<T> {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Pub<T>`
     impl<T: PrivTr> PubTr for Pub<T> {} // OK, trait impl predicates
@@ -75,12 +79,18 @@ mod generics {
     pub struct Pub<T = u8>(T);
     trait PrivTr<T> {}
     pub trait PubTr<T> {}
+    impl PrivTr<Priv<()>> for () {}
 
     pub trait Tr1: PrivTr<Pub> {}
         //~^ ERROR trait `generics::PrivTr<generics::Pub>` is more private than the item `generics::Tr1`
     pub trait Tr2: PubTr<Priv> {} //~ ERROR type `generics::Priv` is more private than the item `generics::Tr2`
     pub trait Tr3: PubTr<[Priv; 1]> {} //~ ERROR type `generics::Priv` is more private than the item `generics::Tr3`
     pub trait Tr4: PubTr<Pub<Priv>> {} //~ ERROR type `generics::Priv` is more private than the item `Tr4`
+
+    pub trait Tr5 {
+        fn required() -> impl PrivTr<Priv<()>>;
+        fn provided() -> impl PrivTr<Priv<()>> {}
+    }
 }
 
 mod impls {
diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr
index 3743879ffa6..c2a57e3b82c 100644
--- a/tests/ui/privacy/private-in-public-warn.stderr
+++ b/tests/ui/privacy/private-in-public-warn.stderr
@@ -130,7 +130,7 @@ LL |         type Alias = Priv;
    |         ^^^^^^^^^^ can't leak private type
 
 error: trait `traits::PrivTr` is more private than the item `traits::Alias`
-  --> $DIR/private-in-public-warn.rs:41:5
+  --> $DIR/private-in-public-warn.rs:42:5
    |
 LL |     pub type Alias<T: PrivTr> = T;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ type alias `traits::Alias` is reachable at visibility `pub(crate)`
@@ -147,7 +147,7 @@ LL | #![deny(private_interfaces, private_bounds)]
    |                             ^^^^^^^^^^^^^^
 
 error: trait `traits::PrivTr` is more private than the item `traits::Tr1`
-  --> $DIR/private-in-public-warn.rs:43:5
+  --> $DIR/private-in-public-warn.rs:44:5
    |
 LL |     pub trait Tr1: PrivTr {}
    |     ^^^^^^^^^^^^^^^^^^^^^ trait `traits::Tr1` is reachable at visibility `pub(crate)`
@@ -159,7 +159,7 @@ LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits::PrivTr` is more private than the item `traits::Tr2`
-  --> $DIR/private-in-public-warn.rs:44:5
+  --> $DIR/private-in-public-warn.rs:45:5
    |
 LL |     pub trait Tr2<T: PrivTr> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ trait `traits::Tr2` is reachable at visibility `pub(crate)`
@@ -171,7 +171,7 @@ LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits::PrivTr` is more private than the item `traits::Tr3::Alias`
-  --> $DIR/private-in-public-warn.rs:46:9
+  --> $DIR/private-in-public-warn.rs:47:9
    |
 LL |         type Alias: PrivTr;
    |         ^^^^^^^^^^^^^^^^^^ associated type `traits::Tr3::Alias` is reachable at visibility `pub(crate)`
@@ -183,7 +183,7 @@ LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits::PrivTr` is more private than the item `traits::Tr3::f`
-  --> $DIR/private-in-public-warn.rs:48:9
+  --> $DIR/private-in-public-warn.rs:49:9
    |
 LL |         fn f<T: PrivTr>(arg: T) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits::Tr3::f` is reachable at visibility `pub(crate)`
@@ -195,7 +195,7 @@ LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits::PrivTr` is more private than the item `traits::Pub<T>`
-  --> $DIR/private-in-public-warn.rs:50:5
+  --> $DIR/private-in-public-warn.rs:54:5
    |
 LL |     impl<T: PrivTr> Pub<T> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^ implementation `traits::Pub<T>` is reachable at visibility `pub(crate)`
@@ -207,103 +207,103 @@ LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits_where::PrivTr` is more private than the item `traits_where::Alias`
-  --> $DIR/private-in-public-warn.rs:59:5
+  --> $DIR/private-in-public-warn.rs:63:5
    |
 LL |     pub type Alias<T> where T: PrivTr = T;
    |     ^^^^^^^^^^^^^^^^^ type alias `traits_where::Alias` is reachable at visibility `pub(crate)`
    |
 note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:55:5
+  --> $DIR/private-in-public-warn.rs:59:5
    |
 LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr2`
-  --> $DIR/private-in-public-warn.rs:62:5
+  --> $DIR/private-in-public-warn.rs:66:5
    |
 LL |     pub trait Tr2<T> where T: PrivTr {}
    |     ^^^^^^^^^^^^^^^^ trait `traits_where::Tr2` is reachable at visibility `pub(crate)`
    |
 note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:55:5
+  --> $DIR/private-in-public-warn.rs:59:5
    |
 LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr3::f`
-  --> $DIR/private-in-public-warn.rs:65:9
+  --> $DIR/private-in-public-warn.rs:69:9
    |
 LL |         fn f<T>(arg: T) where T: PrivTr {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits_where::Tr3::f` is reachable at visibility `pub(crate)`
    |
 note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:55:5
+  --> $DIR/private-in-public-warn.rs:59:5
    |
 LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `traits_where::PrivTr` is more private than the item `traits_where::Pub<T>`
-  --> $DIR/private-in-public-warn.rs:68:5
+  --> $DIR/private-in-public-warn.rs:72:5
    |
 LL |     impl<T> Pub<T> where T: PrivTr {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation `traits_where::Pub<T>` is reachable at visibility `pub(crate)`
    |
 note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:55:5
+  --> $DIR/private-in-public-warn.rs:59:5
    |
 LL |     trait PrivTr {}
    |     ^^^^^^^^^^^^
 
 error: trait `generics::PrivTr<generics::Pub>` is more private than the item `generics::Tr1`
-  --> $DIR/private-in-public-warn.rs:79:5
+  --> $DIR/private-in-public-warn.rs:84:5
    |
 LL |     pub trait Tr1: PrivTr<Pub> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr1` is reachable at visibility `pub(crate)`
    |
 note: but trait `generics::PrivTr<generics::Pub>` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:76:5
+  --> $DIR/private-in-public-warn.rs:80:5
    |
 LL |     trait PrivTr<T> {}
    |     ^^^^^^^^^^^^^^^
 
 error: type `generics::Priv` is more private than the item `generics::Tr2`
-  --> $DIR/private-in-public-warn.rs:81:5
+  --> $DIR/private-in-public-warn.rs:86:5
    |
 LL |     pub trait Tr2: PubTr<Priv> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr2` is reachable at visibility `pub(crate)`
    |
 note: but type `generics::Priv` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:74:5
+  --> $DIR/private-in-public-warn.rs:78:5
    |
 LL |     struct Priv<T = u8>(T);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: type `generics::Priv` is more private than the item `generics::Tr3`
-  --> $DIR/private-in-public-warn.rs:82:5
+  --> $DIR/private-in-public-warn.rs:87:5
    |
 LL |     pub trait Tr3: PubTr<[Priv; 1]> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr3` is reachable at visibility `pub(crate)`
    |
 note: but type `generics::Priv` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:74:5
+  --> $DIR/private-in-public-warn.rs:78:5
    |
 LL |     struct Priv<T = u8>(T);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: type `generics::Priv` is more private than the item `Tr4`
-  --> $DIR/private-in-public-warn.rs:83:5
+  --> $DIR/private-in-public-warn.rs:88:5
    |
 LL |     pub trait Tr4: PubTr<Pub<Priv>> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `Tr4` is reachable at visibility `pub(crate)`
    |
 note: but type `generics::Priv` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:74:5
+  --> $DIR/private-in-public-warn.rs:78:5
    |
 LL |     struct Priv<T = u8>(T);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error[E0446]: private type `impls::Priv` in public interface
-  --> $DIR/private-in-public-warn.rs:109:9
+  --> $DIR/private-in-public-warn.rs:119:9
    |
 LL |     struct Priv;
    |     ----------- `impls::Priv` declared as private
@@ -312,19 +312,19 @@ LL |         type Alias = Priv;
    |         ^^^^^^^^^^ can't leak private type
 
 error: type `aliases_pub::Priv` is more private than the item `aliases_pub::<impl Pub2>::f`
-  --> $DIR/private-in-public-warn.rs:180:9
+  --> $DIR/private-in-public-warn.rs:190:9
    |
 LL |         pub fn f(arg: Priv) {}
    |         ^^^^^^^^^^^^^^^^^^^ associated function `aliases_pub::<impl Pub2>::f` is reachable at visibility `pub(crate)`
    |
 note: but type `aliases_pub::Priv` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:153:5
+  --> $DIR/private-in-public-warn.rs:163:5
    |
 LL |     struct Priv;
    |     ^^^^^^^^^^^
 
 error[E0446]: private type `aliases_pub::Priv` in public interface
-  --> $DIR/private-in-public-warn.rs:183:9
+  --> $DIR/private-in-public-warn.rs:193:9
    |
 LL |     struct Priv;
    |     ----------- `aliases_pub::Priv` declared as private
@@ -333,7 +333,7 @@ LL |         type Check = Priv;
    |         ^^^^^^^^^^ can't leak private type
 
 error[E0446]: private type `aliases_pub::Priv` in public interface
-  --> $DIR/private-in-public-warn.rs:186:9
+  --> $DIR/private-in-public-warn.rs:196:9
    |
 LL |     struct Priv;
    |     ----------- `aliases_pub::Priv` declared as private
@@ -342,7 +342,7 @@ LL |         type Check = Priv;
    |         ^^^^^^^^^^ can't leak private type
 
 error[E0446]: private type `aliases_pub::Priv` in public interface
-  --> $DIR/private-in-public-warn.rs:189:9
+  --> $DIR/private-in-public-warn.rs:199:9
    |
 LL |     struct Priv;
    |     ----------- `aliases_pub::Priv` declared as private
@@ -351,7 +351,7 @@ LL |         type Check = Priv;
    |         ^^^^^^^^^^ can't leak private type
 
 error[E0446]: private type `aliases_pub::Priv` in public interface
-  --> $DIR/private-in-public-warn.rs:192:9
+  --> $DIR/private-in-public-warn.rs:202:9
    |
 LL |     struct Priv;
    |     ----------- `aliases_pub::Priv` declared as private
@@ -360,43 +360,43 @@ LL |         type Check = Priv;
    |         ^^^^^^^^^^ can't leak private type
 
 error: trait `PrivTr1` is more private than the item `aliases_priv::Tr1`
-  --> $DIR/private-in-public-warn.rs:222:5
+  --> $DIR/private-in-public-warn.rs:232:5
    |
 LL |     pub trait Tr1: PrivUseAliasTr {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr1` is reachable at visibility `pub(crate)`
    |
 note: but trait `PrivTr1` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:208:5
+  --> $DIR/private-in-public-warn.rs:218:5
    |
 LL |     trait PrivTr1<T = u8> {
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: trait `PrivTr1<Priv2>` is more private than the item `aliases_priv::Tr2`
-  --> $DIR/private-in-public-warn.rs:224:5
+  --> $DIR/private-in-public-warn.rs:234:5
    |
 LL |     pub trait Tr2: PrivUseAliasTr<PrivAlias> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)`
    |
 note: but trait `PrivTr1<Priv2>` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:208:5
+  --> $DIR/private-in-public-warn.rs:218:5
    |
 LL |     trait PrivTr1<T = u8> {
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: type `Priv2` is more private than the item `aliases_priv::Tr2`
-  --> $DIR/private-in-public-warn.rs:224:5
+  --> $DIR/private-in-public-warn.rs:234:5
    |
 LL |     pub trait Tr2: PrivUseAliasTr<PrivAlias> {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)`
    |
 note: but type `Priv2` is only usable at visibility `pub(self)`
-  --> $DIR/private-in-public-warn.rs:206:5
+  --> $DIR/private-in-public-warn.rs:216:5
    |
 LL |     struct Priv2;
    |     ^^^^^^^^^^^^
 
 warning: bounds on generic parameters in type aliases are not enforced
-  --> $DIR/private-in-public-warn.rs:41:23
+  --> $DIR/private-in-public-warn.rs:42:23
    |
 LL |     pub type Alias<T: PrivTr> = T;
    |                     --^^^^^^
@@ -410,7 +410,7 @@ LL |     pub type Alias<T: PrivTr> = T;
    = note: `#[warn(type_alias_bounds)]` on by default
 
 warning: where clauses on type aliases are not enforced
-  --> $DIR/private-in-public-warn.rs:59:29
+  --> $DIR/private-in-public-warn.rs:63:29
    |
 LL |     pub type Alias<T> where T: PrivTr = T;
    |                       ------^^^^^^^^^
diff --git a/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs b/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs
index 4eeecdc0569..75640147026 100644
--- a/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs
+++ b/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs
@@ -1,5 +1,6 @@
 pub struct OtherType;
 pub trait OtherTrait {}
+impl OtherTrait for OtherType {}
 
 #[macro_export]
 macro_rules! m {
diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs
index 877029f3de3..b85f2754fb1 100644
--- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs
+++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs
@@ -9,10 +9,10 @@
 #![deny(exported_private_dependencies)]
 
 // This crate is a private dependency
-// FIXME: This should trigger.
 pub extern crate priv_dep;
+//~^ ERROR crate `priv_dep` from private dependency 'priv_dep' is re-exported
 // This crate is a public dependency
-extern crate pub_dep;
+pub extern crate pub_dep;
 // This crate is a private dependency
 extern crate pm;
 
@@ -44,8 +44,12 @@ impl PublicType {
 
 pub trait MyPubTrait {
     type Foo: OtherTrait;
+    //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
+
+    fn required() -> impl OtherTrait;
+
+    fn provided() -> impl OtherTrait { OtherType }
 }
-//~^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
 
 pub trait WithSuperTrait: OtherTrait {}
 //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
@@ -91,16 +95,16 @@ pub struct AllowedPrivType {
     pub allowed: OtherType,
 }
 
-// FIXME: This should trigger.
 pub use priv_dep::m;
-// FIXME: This should trigger.
+//~^ ERROR macro `m` from private dependency 'priv_dep' is re-exported
 pub use pm::fn_like;
-// FIXME: This should trigger.
+//~^ ERROR macro `fn_like` from private dependency 'pm' is re-exported
 pub use pm::PmDerive;
-// FIXME: This should trigger.
+//~^ ERROR macro `PmDerive` from private dependency 'pm' is re-exported
 pub use pm::pm_attr;
+//~^ ERROR macro `pm_attr` from private dependency 'pm' is re-exported
 
-// FIXME: This should trigger.
 pub use priv_dep::E::V1;
+//~^ ERROR variant `V1` from private dependency 'priv_dep' is re-exported
 
 fn main() {}
diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr
index adfe13424cd..24bd071567f 100644
--- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr
+++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr
@@ -1,8 +1,8 @@
-error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:29:5
+error: crate `priv_dep` from private dependency 'priv_dep' is re-exported
+  --> $DIR/pub-priv1.rs:12:1
    |
-LL |     pub field: OtherType,
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL | pub extern crate priv_dep;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/pub-priv1.rs:9:9
@@ -10,6 +10,42 @@ note: the lint level is defined here
 LL | #![deny(exported_private_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: macro `m` from private dependency 'priv_dep' is re-exported
+  --> $DIR/pub-priv1.rs:98:9
+   |
+LL | pub use priv_dep::m;
+   |         ^^^^^^^^^^^
+
+error: macro `fn_like` from private dependency 'pm' is re-exported
+  --> $DIR/pub-priv1.rs:100:9
+   |
+LL | pub use pm::fn_like;
+   |         ^^^^^^^^^^^
+
+error: derive macro `PmDerive` from private dependency 'pm' is re-exported
+  --> $DIR/pub-priv1.rs:102:9
+   |
+LL | pub use pm::PmDerive;
+   |         ^^^^^^^^^^^^
+
+error: attribute macro `pm_attr` from private dependency 'pm' is re-exported
+  --> $DIR/pub-priv1.rs:104:9
+   |
+LL | pub use pm::pm_attr;
+   |         ^^^^^^^^^^^
+
+error: variant `V1` from private dependency 'priv_dep' is re-exported
+  --> $DIR/pub-priv1.rs:107:9
+   |
+LL | pub use priv_dep::E::V1;
+   |         ^^^^^^^^^^^^^^^
+
+error: type `OtherType` from private dependency 'priv_dep' in public interface
+  --> $DIR/pub-priv1.rs:29:5
+   |
+LL |     pub field: OtherType,
+   |     ^^^^^^^^^^^^^^^^^^^^
+
 error: type `OtherType` from private dependency 'priv_dep' in public interface
   --> $DIR/pub-priv1.rs:36:5
    |
@@ -29,66 +65,66 @@ LL |     type Foo: OtherTrait;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:50:1
+  --> $DIR/pub-priv1.rs:54:1
    |
 LL | pub trait WithSuperTrait: OtherTrait {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:59:5
+  --> $DIR/pub-priv1.rs:63:5
    |
 LL |     type X = OtherType;
    |     ^^^^^^
 
 error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:63:1
+  --> $DIR/pub-priv1.rs:67:1
    |
 LL | pub fn in_bounds<T: OtherTrait>(x: T) { unimplemented!() }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:66:1
+  --> $DIR/pub-priv1.rs:70:1
    |
 LL | pub fn private_in_generic() -> std::num::Saturating<OtherType> { unimplemented!() }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:69:1
+  --> $DIR/pub-priv1.rs:73:1
    |
 LL | pub static STATIC: OtherType = OtherType;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:72:1
+  --> $DIR/pub-priv1.rs:76:1
    |
 LL | pub const CONST: OtherType = OtherType;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:75:1
+  --> $DIR/pub-priv1.rs:79:1
    |
 LL | pub type Alias = OtherType;
    | ^^^^^^^^^^^^^^
 
 error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:80:1
+  --> $DIR/pub-priv1.rs:84:1
    |
 LL | impl OtherTrait for PublicWithPrivateImpl {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:85:1
+  --> $DIR/pub-priv1.rs:89:1
    |
 LL | impl PubTraitOnPrivate for OtherType {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:85:1
+  --> $DIR/pub-priv1.rs:89:1
    |
 LL | impl PubTraitOnPrivate for OtherType {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 14 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
new file mode 100644
index 00000000000..13f3065e442
--- /dev/null
+++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs
@@ -0,0 +1,13 @@
+// We should not emit sealed traits note, see issue #143392
+
+mod inner {
+    pub trait TraitA {}
+
+    pub trait TraitB: TraitA {}
+}
+
+struct Struct;
+
+impl inner::TraitB for Struct {} //~ ERROR the trait bound `Struct: TraitA` is not satisfied [E0277]
+
+fn main(){}
diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
new file mode 100644
index 00000000000..f80d985ad6e
--- /dev/null
+++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `Struct: TraitA` is not satisfied
+  --> $DIR/false-sealed-traits-note.rs:11:24
+   |
+LL | impl inner::TraitB for Struct {}
+   |                        ^^^^^^ the trait `TraitA` is not implemented for `Struct`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/false-sealed-traits-note.rs:4:5
+   |
+LL |     pub trait TraitA {}
+   |     ^^^^^^^^^^^^^^^^
+note: required by a bound in `TraitB`
+  --> $DIR/false-sealed-traits-note.rs:6:23
+   |
+LL |     pub trait TraitB: TraitA {}
+   |                       ^^^^^^ required by this bound in `TraitB`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr
index 23c93a4ed8b..4244c11eb3e 100644
--- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr
+++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr
@@ -10,13 +10,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module
 LL | #[doc(alias = "foo")]
    |       ^^^^^^^^^^^^^
 
-error: `#[doc(alias = "...")]` isn't allowed on implementation block
+error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block
   --> $DIR/check-doc-alias-attr-location.rs:12:7
    |
 LL | #[doc(alias = "bar")]
    |       ^^^^^^^^^^^^^
 
-error: `#[doc(alias = "...")]` isn't allowed on implementation block
+error: `#[doc(alias = "...")]` isn't allowed on trait implementation block
   --> $DIR/check-doc-alias-attr-location.rs:18:7
    |
 LL | #[doc(alias = "foobar")]
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/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
index ecd669059ed..ce2fb8235cc 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
@@ -4,11 +4,11 @@ struct Foo<'a>(&'a str);
 
 impl<'b> Foo<'b> {
     fn a<'a>(self: Self, a: &'a str) -> &str {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         a
     }
     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
-        //~^ WARNING lifetime flowing from input to output with different syntax
+        //~^ WARNING eliding a lifetime that's named elsewhere is confusing
         a
     }
 }
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
index 5351bf3c94c..7108fa1a290 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/ignore-non-reference-lifetimes.rs:6:30
    |
 LL |     fn a<'a>(self: Self, a: &'a str) -> &str {
-   |                              ^^         ---- the lifetime gets resolved as `'a`
+   |                              ^^         ---- the same lifetime is elided here
    |                              |
-   |                              this lifetime flows to the output
+   |                              the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'a`
+help: consistently use `'a`
    |
 LL |     fn a<'a>(self: Self, a: &'a str) -> &'a str {
    |                                          ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/ignore-non-reference-lifetimes.rs:10:33
    |
 LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
-   |                                 ^^         ---- the lifetime gets resolved as `'a`
+   |                                 ^^         ---- the same lifetime is elided here
    |                                 |
-   |                                 this lifetime flows to the output
+   |                                 the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str {
    |                                             ++
diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs
index f839ab03a60..0093971fee4 100644
--- a/tests/ui/self/self_lifetime-async.rs
+++ b/tests/ui/self/self_lifetime-async.rs
@@ -4,13 +4,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr
index a9c1be2e808..43dc96abdc2 100644
--- a/tests/ui/self/self_lifetime-async.stderr
+++ b/tests/ui/self/self_lifetime-async.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime-async.rs:6:29
    |
 LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-   |                             ^^             --- the lifetime gets resolved as `'b`
+   |                             ^^             --- the same lifetime is elided here
    |                             |
-   |                             this lifetime flows to the output
+   |                             the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'b`
+help: consistently use `'b`
    |
 LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 }
    |                                             ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime-async.rs:12:42
    |
 LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-   |                                          ^^        --- the lifetime gets resolved as `'a`
+   |                                          ^^        --- the same lifetime is elided here
    |                                          |
-   |                                          this lifetime flows to the output
+   |                                          the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg }
    |                                                     ++
diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs
index aaa31f85ad5..190809af22f 100644
--- a/tests/ui/self/self_lifetime.rs
+++ b/tests/ui/self/self_lifetime.rs
@@ -5,13 +5,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-    //~^ WARNING lifetime flowing from input to output with different syntax
+    //~^ WARNING eliding a lifetime that's named elsewhere is confusing
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr
index ec676e69cf6..4f9b2fcd2ad 100644
--- a/tests/ui/self/self_lifetime.stderr
+++ b/tests/ui/self/self_lifetime.stderr
@@ -1,26 +1,28 @@
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime.rs:7:23
    |
 LL |     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
-   |                       ^^             --- the lifetime gets resolved as `'b`
+   |                       ^^             --- the same lifetime is elided here
    |                       |
-   |                       this lifetime flows to the output
+   |                       the lifetime is named here
    |
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
    = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
-help: one option is to consistently use `'b`
+help: consistently use `'b`
    |
 LL |     fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 }
    |                                       ++
 
-warning: lifetime flowing from input to output with different syntax can be confusing
+warning: eliding a lifetime that's named elsewhere is confusing
   --> $DIR/self_lifetime.rs:13:36
    |
 LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
-   |                                    ^^        --- the lifetime gets resolved as `'a`
+   |                                    ^^        --- the same lifetime is elided here
    |                                    |
-   |                                    this lifetime flows to the output
+   |                                    the lifetime is named here
    |
-help: one option is to consistently use `'a`
+   = help: the same lifetime is referred to in inconsistent ways, making the signature confusing
+help: consistently use `'a`
    |
 LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg }
    |                                               ++
diff --git a/tests/ui/lexical-scopes.rs b/tests/ui/shadowed/shadowing-generic-item.rs
index 46cfdf1efa8..c3a0ced04e7 100644
--- a/tests/ui/lexical-scopes.rs
+++ b/tests/ui/shadowed/shadowing-generic-item.rs
@@ -1,3 +1,5 @@
+//! Test that generic parameters shadow structs and modules with the same name.
+
 struct T { i: i32 }
 fn f<T>() {
     let t = T { i: 0 }; //~ ERROR expected struct, variant or union type, found type parameter `T`
diff --git a/tests/ui/lexical-scopes.stderr b/tests/ui/shadowed/shadowing-generic-item.stderr
index f0eaa1a5c64..55a0bb36ea8 100644
--- a/tests/ui/lexical-scopes.stderr
+++ b/tests/ui/shadowed/shadowing-generic-item.stderr
@@ -1,5 +1,5 @@
 error[E0574]: expected struct, variant or union type, found type parameter `T`
-  --> $DIR/lexical-scopes.rs:3:13
+  --> $DIR/shadowing-generic-item.rs:5:13
    |
 LL | struct T { i: i32 }
    |        - you might have meant to refer to this struct
@@ -9,7 +9,7 @@ LL |     let t = T { i: 0 };
    |             ^ not a struct, variant or union type
 
 error[E0599]: no function or associated item named `f` found for type parameter `Foo` in the current scope
-  --> $DIR/lexical-scopes.rs:10:10
+  --> $DIR/shadowing-generic-item.rs:12:10
    |
 LL | fn g<Foo>() {
    |      --- function or associated item `f` not found for this type parameter
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/incomplete-inference-issue-143992.current_sized_hierarchy.stderr b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.current_sized_hierarchy.stderr
new file mode 100644
index 00000000000..b904b784df7
--- /dev/null
+++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.current_sized_hierarchy.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/incomplete-inference-issue-143992.rs:30:28
+   |
+LL |     let _x = T::Assoc::new(());
+   |              ------------- ^^ expected `[u32; 1]`, found `()`
+   |              |
+   |              arguments to this function are incorrect
+   |
+note: associated function defined here
+  --> $DIR/incomplete-inference-issue-143992.rs:21:8
+   |
+LL |     fn new(r: R) -> R {
+   |        ^^^ ----
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr
new file mode 100644
index 00000000000..b904b784df7
--- /dev/null
+++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next_sized_hierarchy.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/incomplete-inference-issue-143992.rs:30:28
+   |
+LL |     let _x = T::Assoc::new(());
+   |              ------------- ^^ expected `[u32; 1]`, found `()`
+   |              |
+   |              arguments to this function are incorrect
+   |
+note: associated function defined here
+  --> $DIR/incomplete-inference-issue-143992.rs:21:8
+   |
+LL |     fn new(r: R) -> R {
+   |        ^^^ ----
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs
new file mode 100644
index 00000000000..b9e65ed2839
--- /dev/null
+++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs
@@ -0,0 +1,33 @@
+//@ compile-flags: --crate-type=lib
+//@ revisions: current next current_sized_hierarchy next_sized_hierarchy
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[current] check-pass
+//@[next] check-pass
+//@[next] compile-flags: -Znext-solver
+//@[next_sized_hierarchy] compile-flags: -Znext-solver
+
+#![cfg_attr(any(current_sized_hierarchy, next_sized_hierarchy), feature(sized_hierarchy))]
+
+// Test that we avoid incomplete inference when normalizing. Without this,
+// `Trait`'s implicit `MetaSized` supertrait requires proving `T::Assoc<_>: MetaSized`
+// before checking the `new` arguments, resulting in eagerly constraining the inference
+// var to `u32`. This is undesirable and would breaking code.
+
+pub trait Trait {
+    type Assoc<G>: OtherTrait<G>;
+}
+
+pub trait OtherTrait<R> {
+    fn new(r: R) -> R {
+        r
+    }
+}
+
+pub fn function<T: Trait>()
+where
+    T::Assoc<[u32; 1]>: Clone,
+{
+    let _x = T::Assoc::new(());
+    //[next_sized_hierarchy]~^ ERROR mismatched types
+    //[current_sized_hierarchy]~^^ ERROR mismatched types
+}
diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr
deleted file mode 100644
index e90548aa78c..00000000000
--- a/tests/ui/sized-hierarchy/overflow.current.stderr
+++ /dev/null
@@ -1,45 +0,0 @@
-error[E0275]: overflow evaluating the requirement `Element: MetaSized`
-  --> $DIR/overflow.rs:16:16
-   |
-LL | struct Element(<Box<Box<Element>> as ParseTokens>::Output);
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: required for `Box<Element>` to implement `ParseTokens`
-  --> $DIR/overflow.rs:12:31
-   |
-LL | impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> {
-   |      -                        ^^^^^^^^^^^     ^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
-   = note: 1 redundant requirement hidden
-   = note: required for `Box<Box<Element>>` to implement `ParseTokens`
-
-error[E0275]: overflow evaluating the requirement `Box<Element>: ParseTokens`
-  --> $DIR/overflow.rs:18:22
-   |
-LL | impl ParseTokens for Element {
-   |                      ^^^^^^^
-   |
-note: required for `Box<Box<Element>>` to implement `ParseTokens`
-  --> $DIR/overflow.rs:12:31
-   |
-LL | impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> {
-   |         -----------           ^^^^^^^^^^^     ^^^^^^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required because it appears within the type `Element`
-  --> $DIR/overflow.rs:16:8
-   |
-LL | struct Element(<Box<Box<Element>> as ParseTokens>::Output);
-   |        ^^^^^^^
-note: required by a bound in `ParseTokens`
-  --> $DIR/overflow.rs:9:1
-   |
-LL | / trait ParseTokens {
-LL | |     type Output;
-LL | | }
-   | |_^ required by this bound in `ParseTokens`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/sized-hierarchy/overflow.rs b/tests/ui/sized-hierarchy/overflow.rs
index e1af4885e53..f8e5dd5d402 100644
--- a/tests/ui/sized-hierarchy/overflow.rs
+++ b/tests/ui/sized-hierarchy/overflow.rs
@@ -1,9 +1,13 @@
 //@ compile-flags: --crate-type=lib
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
+//@[current] check-pass
 //@[next] check-pass
 //@[next] compile-flags: -Znext-solver
 
+// FIXME(sized_hierarchy): this is expected to fail in the old solver when there
+// isn't a temporary revert of the `sized_hierarchy` feature
+
 use std::marker::PhantomData;
 
 trait ParseTokens {
@@ -14,8 +18,6 @@ impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> {
 }
 
 struct Element(<Box<Box<Element>> as ParseTokens>::Output);
-//[current]~^ ERROR overflow evaluating
 impl ParseTokens for Element {
-//[current]~^ ERROR overflow evaluating
     type Output = ();
 }
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/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index b9c768812c8..a21a48997ee 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,57 +1,57 @@
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const_trait_impl.rs:36:9
    |
 LL | impl<T: [const] Debug> const A for T {
    |         ^^^^^^^ can't be applied to `Debug`
    |
-note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Debug` can't be used with `[const]` because it isn't `const`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const_trait_impl.rs:42:9
    |
 LL | impl<T: [const] Debug + [const] Sup> const A for T {
    |         ^^^^^^^ can't be applied to `Debug`
    |
-note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Debug` can't be used with `[const]` because it isn't `const`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const_trait_impl.rs:48:9
    |
 LL | impl<T: [const] Debug + [const] Sub> const A for T {
    |         ^^^^^^^ can't be applied to `Debug`
    |
-note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Debug` can't be used with `[const]` because it isn't `const`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const_trait_impl.rs:42:9
    |
 LL | impl<T: [const] Debug + [const] Sup> const A for T {
    |         ^^^^^^^ can't be applied to `Debug`
    |
-note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Debug` can't be used with `[const]` because it isn't `const`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const_trait_impl.rs:36:9
    |
 LL | impl<T: [const] Debug> const A for T {
    |         ^^^^^^^ can't be applied to `Debug`
    |
-note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Debug` can't be used with `[const]` because it isn't `const`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const_trait_impl.rs:48:9
    |
 LL | impl<T: [const] Debug + [const] Sub> const A for T {
    |         ^^^^^^^ can't be applied to `Debug`
    |
-note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
+note: `Debug` can't be used with `[const]` because it isn't `const`
   --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs
index c3e72e83948..8a37f19ffb0 100644
--- a/tests/ui/stability-attribute/missing-const-stability.rs
+++ b/tests/ui/stability-attribute/missing-const-stability.rs
@@ -20,8 +20,7 @@ impl Foo {
 }
 
 #[stable(feature = "stable", since = "1.0.0")]
-#[const_trait]
-pub trait Bar {
+pub const trait Bar {
 //~^ ERROR trait has missing const stability attribute
     #[stable(feature = "stable", since = "1.0.0")]
     fn fun();
diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr
index 09461e6fb54..5748e20cd2b 100644
--- a/tests/ui/stability-attribute/missing-const-stability.stderr
+++ b/tests/ui/stability-attribute/missing-const-stability.stderr
@@ -2,29 +2,25 @@ error: function has missing const stability attribute
   --> $DIR/missing-const-stability.rs:7:1
    |
 LL | pub const fn foo() {}
-   | ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^
 
 error: trait has missing const stability attribute
-  --> $DIR/missing-const-stability.rs:24:1
+  --> $DIR/missing-const-stability.rs:23:1
    |
-LL | / pub trait Bar {
-LL | |
-LL | |     #[stable(feature = "stable", since = "1.0.0")]
-LL | |     fn fun();
-LL | | }
-   | |_^
+LL | pub const trait Bar {
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: function has missing const stability attribute
-  --> $DIR/missing-const-stability.rs:37:1
+  --> $DIR/missing-const-stability.rs:36:1
    |
 LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: associated function has missing const stability attribute
   --> $DIR/missing-const-stability.rs:16:5
    |
 LL |     pub const fn foo() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr
index a6d1ebf2945..d33bb53360b 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity-3.stderr
@@ -1,10 +1,8 @@
 error: macro has missing stability attribute
   --> $DIR/stability-attribute-sanity-3.rs:8:1
    |
-LL | / macro_rules! mac {
-LL | |     () => ()
-LL | | }
-   | |_^
+LL | macro_rules! mac {
+   | ^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
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/structs/default-field-values/const-trait-default-field-value.rs b/tests/ui/structs/default-field-values/const-trait-default-field-value.rs
new file mode 100644
index 00000000000..60c22efabc4
--- /dev/null
+++ b/tests/ui/structs/default-field-values/const-trait-default-field-value.rs
@@ -0,0 +1,37 @@
+//@ check-pass
+
+// Ensure that `default_field_values` and `const_default` interact properly.
+
+#![feature(const_default)]
+#![feature(const_trait_impl)]
+#![feature(default_field_values)]
+#![feature(derive_const)]
+
+#[derive(PartialEq, Eq, Debug)]
+#[derive_const(Default)]
+struct S {
+    r: Option<String> = <Option<_> as Default>::default(),
+    s: String = String::default(),
+    o: Option<String> = Option::<String>::default(),
+    p: std::marker::PhantomData<()> = std::marker::PhantomData::default(),
+    q: Option<String> = <Option<String> as Default>::default(),
+    t: Option<String> = Option::default(),
+    v: Option<String> = const { Option::default() },
+}
+
+const _: S = S { .. };
+const _: S = const { S { .. } };
+const _: S = S::default();
+const _: S = const { S::default() };
+
+fn main() {
+    let s = S { .. };
+    assert_eq!(s.r, None);
+    assert_eq!(&s.s, "");
+    assert_eq!(s.o, None);
+    assert_eq!(s.p, std::marker::PhantomData);
+    assert_eq!(s.q, None);
+    assert_eq!(s.t, None);
+    assert_eq!(s.v, None);
+    assert_eq!(s, S::default());
+}
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/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index 167262dcf06..a028f433172 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17hc88b9d80a69d119aE)
+error: symbol-name(_ZN5basic4main17h1dddcfd03744167fE)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::hc88b9d80a69d119a)
+error: demangling(basic::main::h1dddcfd03744167f)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index 4e17bdc4577..14cbd877d9f 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hbddb77d6f71afb32E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h4b3099ec5dc5d306E)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hbddb77d6f71afb32)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h4b3099ec5dc5d306)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/struct-ctor-mangling.rs b/tests/ui/symbol-names/struct-constructor-mangling.rs
index f32cbb7aaae..ec8791e2154 100644
--- a/tests/ui/struct-ctor-mangling.rs
+++ b/tests/ui/symbol-names/struct-constructor-mangling.rs
@@ -1,3 +1,5 @@
+//! Test that the symbol mangling of Foo-the-constructor-function versus Foo-the-type do not collide
+
 //@ run-pass
 
 fn size_of_val<T>(_: &T) -> usize {
@@ -6,8 +8,6 @@ fn size_of_val<T>(_: &T) -> usize {
 
 struct Foo(#[allow(dead_code)] i64);
 
-// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of
-// `typeof Foo` (the function type of the `struct` constructor) don't collide.
 fn main() {
     size_of_val(&Foo(0));
     size_of_val(&Foo);
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 910582ae4d9..2049c531abd 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -94,7 +94,7 @@ body:
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
                                                                                                 variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
-                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
+                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
                                                                                         args: []
                                                                                         variant_index: 0
                                                                                         subpatterns: [
@@ -108,7 +108,7 @@ body:
                                                                                                                 did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar)
                                                                                                                 variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags:  }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags:  }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags:  }]
                                                                                                                 flags: IS_ENUM
-                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 10333377570083945360 }
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 7908585036048874241 }
                                                                                                         args: []
                                                                                                         variant_index: 0
                                                                                                         subpatterns: []
@@ -156,7 +156,7 @@ body:
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
                                                                                                 variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
-                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
+                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
                                                                                         args: []
                                                                                         variant_index: 0
                                                                                         subpatterns: [
@@ -208,7 +208,7 @@ body:
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
                                                                                                 variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
-                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
+                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 }
                                                                                         args: []
                                                                                         variant_index: 1
                                                                                         subpatterns: []
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/conditionally-const-invalid-places.stderr b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr
index d0dd9502915..010b1584643 100644
--- a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr
+++ b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr
@@ -72,7 +72,7 @@ error: `[const]` is not allowed here
 LL |     type Type<T: [const] Trait>: [const] Trait;
    |                  ^^^^^^^
    |
-note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
+note: associated types in non-`const` traits cannot have `[const]` trait bounds
   --> $DIR/conditionally-const-invalid-places.rs:25:5
    |
 LL |     type Type<T: [const] Trait>: [const] Trait;
@@ -84,7 +84,7 @@ error: `[const]` is not allowed here
 LL |     type Type<T: [const] Trait>: [const] Trait;
    |                                  ^^^^^^^
    |
-note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
+note: associated types in non-`const` traits cannot have `[const]` trait bounds
   --> $DIR/conditionally-const-invalid-places.rs:25:5
    |
 LL |     type Type<T: [const] Trait>: [const] Trait;
@@ -180,7 +180,7 @@ error: `[const]` is not allowed here
 LL | trait Child0: [const] Trait {}
    |               ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/conditionally-const-invalid-places.rs:52:1
    |
 LL | trait Child0: [const] Trait {}
@@ -192,7 +192,7 @@ error: `[const]` is not allowed here
 LL | trait Child1 where Self: [const] Trait {}
    |                          ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/conditionally-const-invalid-places.rs:53:1
    |
 LL | trait Child1 where Self: [const] Trait {}
diff --git a/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs b/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs
new file mode 100644
index 00000000000..81acce65f2a
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+
+#![feature(const_clone)]
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait A where Self::Target: [const] Clone {
+    type Target;
+}
+
+const fn foo<T>() where T: [const] A {}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
index ae31d9ae0ac..baded179201 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
@@ -4,10 +4,10 @@
 trait NonConst {}
 
 const fn perform<T: [const] NonConst>() {}
-//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits
-//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~^ ERROR `[const]` can only be applied to `const` traits
+//~| ERROR `[const]` can only be applied to `const` traits
 
 fn operate<T: const NonConst>() {}
-//~^ ERROR `const` can only be applied to `#[const_trait]` traits
+//~^ ERROR `const` can only be applied to `const` traits
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
index 6c68e4ec3ac..304d81bb917 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
@@ -1,33 +1,33 @@
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform<T: [const] NonConst>() {}
    |                     ^^^^^^^ can't be applied to `NonConst`
    |
-help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `NonConst` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait NonConst {}
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform<T: [const] NonConst>() {}
    |                     ^^^^^^^ can't be applied to `NonConst`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `NonConst` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait NonConst {}
    | ++++++++++++++
 
-error: `const` can only be applied to `#[const_trait]` traits
+error: `const` can only be applied to `const` traits
   --> $DIR/const-bounds-non-const-trait.rs:10:15
    |
 LL | fn operate<T: const NonConst>() {}
    |               ^^^^^ can't be applied to `NonConst`
    |
-help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `NonConst` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait NonConst {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
index 6bea664b65f..176ae091a41 100644
--- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
@@ -4,6 +4,6 @@
 pub trait A {}
 
 impl const A for () {}
-//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`
+//~^ ERROR: const `impl` for trait `A` which is not `const`
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
index c728eda069e..bf73436b78d 100644
--- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
@@ -1,12 +1,12 @@
-error: const `impl` for trait `A` which is not marked with `#[const_trait]`
+error: const `impl` for trait `A` which is not `const`
   --> $DIR/const-impl-requires-const-trait.rs:6:12
    |
 LL | impl const A for () {}
    |            ^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
-help: mark `A` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `A` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] pub trait A {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs
index dc960422a4a..da28d9a47c3 100644
--- a/tests/ui/traits/const-traits/const-impl-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-trait.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -Znext-solver
 //@ known-bug: #110395
 
-// Broken until we have `const PartialEq` impl in stdlib
+// Broken until `(): const PartialEq`
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, const_cmp, const_destruct)]
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
index 1d1da9b0e3d..658132441c2 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs
@@ -1,9 +1,7 @@
 #![feature(const_trait_impl)]
-// FIXME(const_trait_impl) add effects
 //@ edition: 2021
 
-#[const_trait]
-trait Trait {}
+const trait Trait {}
 
 fn main() {
     let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types
@@ -14,7 +12,7 @@ fn main() {
 trait NonConst {}
 const fn handle(_: &dyn const NonConst) {}
 //~^ ERROR const trait bounds are not allowed in trait object types
-//~| ERROR `const` can only be applied to `#[const_trait]` traits
+//~| ERROR `const` can only be applied to `const` traits
 const fn take(_: &dyn [const] NonConst) {}
 //~^ ERROR `[const]` is not allowed here
-//~| ERROR `[const]` can only be applied to `#[const_trait]` traits
+//~| ERROR `[const]` can only be applied to `const` traits
diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
index 06e0493024c..3ba5da39106 100644
--- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
+++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr
@@ -1,11 +1,11 @@
 error: const trait bounds are not allowed in trait object types
-  --> $DIR/const-trait-bounds-trait-objects.rs:9:17
+  --> $DIR/const-trait-bounds-trait-objects.rs:7:17
    |
 LL |     let _: &dyn const Trait;
    |                 ^^^^^^^^^^^
 
 error: `[const]` is not allowed here
-  --> $DIR/const-trait-bounds-trait-objects.rs:10:17
+  --> $DIR/const-trait-bounds-trait-objects.rs:8:17
    |
 LL |     let _: &dyn [const] Trait;
    |                 ^^^^^^^
@@ -13,37 +13,37 @@ LL |     let _: &dyn [const] Trait;
    = note: trait objects cannot have `[const]` trait bounds
 
 error: const trait bounds are not allowed in trait object types
-  --> $DIR/const-trait-bounds-trait-objects.rs:15:25
+  --> $DIR/const-trait-bounds-trait-objects.rs:13:25
    |
 LL | const fn handle(_: &dyn const NonConst) {}
    |                         ^^^^^^^^^^^^^^
 
 error: `[const]` is not allowed here
-  --> $DIR/const-trait-bounds-trait-objects.rs:18:23
+  --> $DIR/const-trait-bounds-trait-objects.rs:16:23
    |
 LL | const fn take(_: &dyn [const] NonConst) {}
    |                       ^^^^^^^
    |
    = note: trait objects cannot have `[const]` trait bounds
 
-error: `const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-trait-bounds-trait-objects.rs:15:25
+error: `const` can only be applied to `const` traits
+  --> $DIR/const-trait-bounds-trait-objects.rs:13:25
    |
 LL | const fn handle(_: &dyn const NonConst) {}
    |                         ^^^^^ can't be applied to `NonConst`
    |
-help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `NonConst` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait NonConst {}
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-trait-bounds-trait-objects.rs:18:23
+error: `[const]` can only be applied to `const` traits
+  --> $DIR/const-trait-bounds-trait-objects.rs:16:23
    |
 LL | const fn take(_: &dyn [const] NonConst) {}
    |                       ^^^^^^^ can't be applied to `NonConst`
    |
-help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `NonConst` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait NonConst {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs
index 04fea1189ae..c0796907855 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs
@@ -1,5 +1,5 @@
 #[derive_const(Debug)] //~ ERROR use of unstable library feature
-//~^ ERROR const `impl` for trait `Debug` which is not marked with `#[const_trait]`
+//~^ ERROR const `impl` for trait `Debug` which is not `const`
 //~| ERROR cannot call non-const method
 pub struct S;
 
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
index 5bde358001c..cbc62d602a4 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
@@ -4,16 +4,17 @@ error[E0658]: use of unstable library feature `derive_const`
 LL | #[derive_const(Debug)]
    |   ^^^^^^^^^^^^
    |
+   = note: see issue #118304 <https://github.com/rust-lang/rust/issues/118304> for more information
    = help: add `#![feature(derive_const)]` 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: const `impl` for trait `Debug` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Debug` which is not `const`
   --> $DIR/derive-const-gate.rs:1:16
    |
 LL | #[derive_const(Debug)]
    |                ^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0015]: cannot call non-const method `Formatter::<'_>::write_str` in constant functions
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index c0bd360ebe5..93638801895 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -1,10 +1,10 @@
-error: const `impl` for trait `Debug` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Debug` which is not `const`
   --> $DIR/derive-const-non-const-type.rs:12:16
    |
 LL | #[derive_const(Debug)]
    |                ^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0015]: cannot call non-const method `Formatter::<'_>::debug_tuple_field1_finish` in constant functions
diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs
index e53b87274d3..47c85980aca 100644
--- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs
+++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs
@@ -4,7 +4,7 @@
 use std::ops::FromResidual;
 
 impl<T> const FromResidual for T {
-    //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+    //~^ ERROR const `impl` for trait `FromResidual` which is not `const`
     //~| ERROR type parameter `T` must be used as the type parameter for some local type
     fn from_residual(t: T) -> _ {
         //~^ ERROR the placeholder `_` is not allowed
diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
index a165ef12060..5c5fba95f02 100644
--- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
+++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
@@ -1,10 +1,10 @@
-error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+error: const `impl` for trait `FromResidual` which is not `const`
   --> $DIR/ice-119717-constant-lifetime.rs:6:15
    |
 LL | impl<T> const FromResidual for T {
    |               ^^^^^^^^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
index 3473be565c1..5e368b9e6a9 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
@@ -6,11 +6,11 @@ struct TryMe;
 struct Error;
 
 impl const FromResidual<Error> for TryMe {}
-//~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+//~^ ERROR const `impl` for trait `FromResidual` which is not `const`
 //~| ERROR not all trait items implemented
 
 impl const Try for TryMe {
-    //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]`
+    //~^ ERROR const `impl` for trait `Try` which is not `const`
     //~| ERROR not all trait items implemented
     type Output = ();
     type Residual = Error;
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
index 41f99c2d375..849d6522cd6 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
@@ -1,10 +1,10 @@
-error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+error: const `impl` for trait `FromResidual` which is not `const`
   --> $DIR/ice-126148-failed-to-normalize.rs:8:12
    |
 LL | impl const FromResidual<Error> for TryMe {}
    |            ^^^^^^^^^^^^^^^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0046]: not all trait items implemented, missing: `from_residual`
@@ -15,13 +15,13 @@ LL | impl const FromResidual<Error> for TryMe {}
    |
    = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }`
 
-error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Try` which is not `const`
   --> $DIR/ice-126148-failed-to-normalize.rs:12:12
    |
 LL | impl const Try for TryMe {
    |            ^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0046]: not all trait items implemented, missing: `from_output`, `branch`
diff --git a/tests/ui/traits/const-traits/imply-always-const.rs b/tests/ui/traits/const-traits/imply-always-const.rs
new file mode 100644
index 00000000000..f6cab0681ec
--- /dev/null
+++ b/tests/ui/traits/const-traits/imply-always-const.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait A where Self::Assoc: const B {
+    type Assoc;
+}
+
+#[const_trait]
+trait B {}
+
+fn needs_b<T: const B>() {}
+
+fn test<T: A>() {
+    needs_b::<T::Assoc>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
deleted file mode 100644
index 89e59e5db6e..00000000000
--- a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0015]: cannot match on `str` in constant functions
-  --> $DIR/match-non-const-eq.rs:7:9
-   |
-LL |         "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts
-   |         ^^^
-   |
-   = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.rs b/tests/ui/traits/const-traits/match-non-const-eq.rs
index 73f8af86bd0..03adb8dc5a4 100644
--- a/tests/ui/traits/const-traits/match-non-const-eq.rs
+++ b/tests/ui/traits/const-traits/match-non-const-eq.rs
@@ -1,11 +1,12 @@
-//@ known-bug: #110395
 //@ revisions: stock gated
-#![cfg_attr(gated, feature(const_trait_impl))]
+#![cfg_attr(gated, feature(const_trait_impl, const_cmp))]
+//@[gated] check-pass
 
 const fn foo(input: &'static str) {
     match input {
-        "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts
-        //FIXME ~^ ERROR cannot match on `str` in constant functions
+        "a" => (),
+        //[stock]~^ ERROR cannot match on `str` in constant functions
+        //[stock]~| ERROR `PartialEq` is not yet stable as a const trait
         _ => (),
     }
 }
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
index 89e59e5db6e..5b662447bde 100644
--- a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
@@ -1,12 +1,26 @@
-error[E0015]: cannot match on `str` in constant functions
+error[E0658]: cannot match on `str` in constant functions
   --> $DIR/match-non-const-eq.rs:7:9
    |
-LL |         "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts
+LL |         "a" => (),
    |         ^^^
    |
    = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = 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: aborting due to 1 previous error
+error: `PartialEq` is not yet stable as a const trait
+  --> $DIR/match-non-const-eq.rs:7:9
+   |
+LL |         "a" => (),
+   |         ^^^
+   |
+help: add `#![feature(const_cmp)]` to the crate attributes to enable
+   |
+LL + #![feature(const_cmp)]
+   |
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0658`.
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/const-traits/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/spec-effectvar-ice.rs
index c85b1746967..46f71b114a3 100644
--- a/tests/ui/traits/const-traits/spec-effectvar-ice.rs
+++ b/tests/ui/traits/const-traits/spec-effectvar-ice.rs
@@ -8,11 +8,11 @@ trait Specialize {}
 trait Foo {}
 
 impl<T> const Foo for T {}
-//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
+//~^ error: const `impl` for trait `Foo` which is not `const`
 
 impl<T> const Foo for T where T: const Specialize {}
-//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
-//~| error: `const` can only be applied to `#[const_trait]` traits
+//~^ error: const `impl` for trait `Foo` which is not `const`
+//~| error: `const` can only be applied to `const` traits
 //~| error: specialization impl does not specialize any associated items
 //~| error: cannot specialize on trait `Specialize`
 
diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr
index 474d96698d5..ef5e58e1c3d 100644
--- a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr
+++ b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr
@@ -1,36 +1,36 @@
-error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Foo` which is not `const`
   --> $DIR/spec-effectvar-ice.rs:10:15
    |
 LL | impl<T> const Foo for T {}
    |               ^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {}
    | ++++++++++++++
 
-error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Foo` which is not `const`
   --> $DIR/spec-effectvar-ice.rs:13:15
    |
 LL | impl<T> const Foo for T where T: const Specialize {}
    |               ^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {}
    | ++++++++++++++
 
-error: `const` can only be applied to `#[const_trait]` traits
+error: `const` can only be applied to `const` traits
   --> $DIR/spec-effectvar-ice.rs:13:34
    |
 LL | impl<T> const Foo for T where T: const Specialize {}
    |                                  ^^^^^ can't be applied to `Specialize`
    |
-help: mark `Specialize` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Specialize` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Specialize {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
index 19f072b289e..0ecbad64bc8 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -4,43 +4,43 @@ error: `[const]` is not allowed here
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/super-traits-fail-2.rs:11:1
    |
 LL | trait Bar: [const] Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
index 4921f78d3ac..0e5b697d1dd 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -1,58 +1,58 @@
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs
index 781dacb81a1..36e7c1c4e4a 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs
@@ -9,11 +9,11 @@ trait Foo {
 
 #[cfg_attr(any(yy, ny), const_trait)]
 trait Bar: [const] Foo {}
-//[ny,nn]~^ ERROR: `[const]` can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
-//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]`
-//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[ny,nn]~^ ERROR: `[const]` can only be applied to `const` traits
+//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits
+//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits
+//[ny]~| ERROR: `[const]` can only be applied to `const` traits
+//[ny]~| ERROR: `[const]` can only be applied to `const` traits
 //[yn,nn]~^^^^^^ ERROR: `[const]` is not allowed here
 
 const fn foo<T: Bar>(x: &T) {
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
index a151349822e..657e8ee82e3 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
@@ -4,7 +4,7 @@ error: `[const]` is not allowed here
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/super-traits-fail-2.rs:11:1
    |
 LL | trait Bar: [const] Foo {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
index 3f48375dd04..a0ae60526ef 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
@@ -4,7 +4,7 @@ error: `[const]` is not allowed here
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/super-traits-fail-3.rs:23:1
    |
 LL | trait Bar: [const] Foo {}
@@ -30,60 +30,60 @@ LL | const fn foo<T: [const] Bar>(x: &T) {
    = 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: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
index 3f48375dd04..a0ae60526ef 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
@@ -4,7 +4,7 @@ error: `[const]` is not allowed here
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/super-traits-fail-3.rs:23:1
    |
 LL | trait Bar: [const] Foo {}
@@ -30,60 +30,60 @@ LL | const fn foo<T: [const] Bar>(x: &T) {
    = 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: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
index 5370f607dec..d74bd346784 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -21,17 +21,17 @@ trait Foo {
 #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
 //[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future
 trait Bar: [const] Foo {}
-//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]`
-//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
-//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
-//[yny]~^^^^ ERROR: `[const]` can only be applied to `#[const_trait]`
-//[yny]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits
+//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits
+//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits
+//[yny]~^^^^ ERROR: `[const]` can only be applied to `const` traits
+//[yny]~| ERROR: `[const]` can only be applied to `const` traits
 //[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `[const]` is not allowed here
 //[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental
 
 const fn foo<T: [const] Bar>(x: &T) {
-    //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]`
-    //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]`
+    //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits
+    //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits
     //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental
     x.a();
     //[yyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
index 89e090b7d1c..c8ec77c2f09 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
@@ -4,66 +4,66 @@ error: `[const]` is not allowed here
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/super-traits-fail-3.rs:23:1
    |
 LL | trait Bar: [const] Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
-help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
index 683eeb73850..a820239cde0 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
@@ -1,58 +1,58 @@
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Foo` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Foo {
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
index 39cfdfe2030..de3664dae84 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
@@ -4,31 +4,31 @@ error: `[const]` is not allowed here
 LL | trait Bar: [const] Foo {}
    |            ^^^^^^^
    |
-note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
+note: this trait is not `const`, so it cannot have `[const]` trait bounds
   --> $DIR/super-traits-fail-3.rs:23:1
    |
 LL | trait Bar: [const] Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
-help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
 
-error: `[const]` can only be applied to `#[const_trait]` traits
+error: `[const]` can only be applied to `const` traits
   --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo<T: [const] Bar>(x: &T) {
    |                 ^^^^^^^ can't be applied to `Bar`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+help: mark `Bar` as `const` to allow it to have `const` implementations
    |
 LL | #[const_trait] trait Bar: [const] Foo {}
    | ++++++++++++++
diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
index a13d9a1e075..b995d6f4f3d 100644
--- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr
+++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
@@ -1,19 +1,19 @@
-error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
+error: const `impl` for trait `Try` which is not `const`
   --> $DIR/trait-default-body-stability.rs:19:12
    |
 LL | impl const Try for T {
    |            ^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
+error: const `impl` for trait `FromResidual` which is not `const`
   --> $DIR/trait-default-body-stability.rs:34:12
    |
 LL | impl const FromResidual for T {
    |            ^^^^^^^^^^^^ this trait is not `const`
    |
-   = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+   = note: marking a trait with `const` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
 error[E0015]: `?` is not allowed on `T` in constant functions
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/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
index 1eb445f4848..8901805a20f 100644
--- a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
@@ -12,13 +12,6 @@ LL | impl<T: Bound, U> Trait<U> for T {
    |         -----     ^^^^^^^^     ^
    |         |
    |         unsatisfied trait bound introduced here
-note: required by a bound in `Bound`
-  --> $DIR/normalizes-to-is-not-productive.rs:8:1
-   |
-LL | / trait Bound {
-LL | |     fn method();
-LL | | }
-   | |_^ required by this bound in `Bound`
 
 error[E0277]: the trait bound `Foo: Bound` is not satisfied
   --> $DIR/normalizes-to-is-not-productive.rs:47:19
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
index 8d8909625ff..d179c805962 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
@@ -19,23 +19,6 @@ error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
 LL |         Self::Assoc: A<T>,
    |                      ^^^^
 
-error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: MetaSized`
-  --> $DIR/normalize-param-env-2.rs:24:22
-   |
-LL |         Self::Assoc: A<T>,
-   |                      ^^^^
-   |
-note: required by a bound in `A`
-  --> $DIR/normalize-param-env-2.rs:9:1
-   |
-LL | / trait A<T> {
-LL | |     type Assoc;
-LL | |
-LL | |     fn f()
-...  |
-LL | | }
-   | |_^ required by this bound in `A`
-
 error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc well-formed`
   --> $DIR/normalize-param-env-2.rs:24:22
    |
@@ -63,6 +46,6 @@ LL |     where
 LL |         Self::Assoc: A<T>,
    |                      ^^^^ required by this bound in `A::f`
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
index 9f7f74f9466..f5fd9ce9864 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
@@ -4,20 +4,6 @@ error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: Trait`
 LL |     <T as Trait>::Assoc: Trait,
    |                          ^^^^^
 
-error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: MetaSized`
-  --> $DIR/normalize-param-env-4.rs:19:26
-   |
-LL |     <T as Trait>::Assoc: Trait,
-   |                          ^^^^^
-   |
-note: required by a bound in `Trait`
-  --> $DIR/normalize-param-env-4.rs:7:1
-   |
-LL | / trait Trait {
-LL | |     type Assoc;
-LL | | }
-   | |_^ required by this bound in `Trait`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.rs b/tests/ui/traits/resolve-impl-before-constrain-check.rs
index 50d1a874551..87f9c241e40 100644
--- a/tests/ui/traits/resolve-impl-before-constrain-check.rs
+++ b/tests/ui/traits/resolve-impl-before-constrain-check.rs
@@ -15,7 +15,6 @@ use foo::*;
 
 fn test() -> impl Sized {
     <() as Callable>::call()
-//~^ ERROR: type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.stderr b/tests/ui/traits/resolve-impl-before-constrain-check.stderr
index 13fbfdb855c..e8e569ba625 100644
--- a/tests/ui/traits/resolve-impl-before-constrain-check.stderr
+++ b/tests/ui/traits/resolve-impl-before-constrain-check.stderr
@@ -4,13 +4,6 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self
 LL |     impl<V: ?Sized> Callable for () {
    |          ^ unconstrained type parameter
 
-error[E0282]: type annotations needed
-  --> $DIR/resolve-impl-before-constrain-check.rs:17:6
-   |
-LL |     <() as Callable>::call()
-   |      ^^ cannot infer type for type parameter `V`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0207, E0282.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
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/underscore-lifetime/raw-underscore-lifetime.rs b/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs
new file mode 100644
index 00000000000..874b3d2c48d
--- /dev/null
+++ b/tests/ui/underscore-lifetime/raw-underscore-lifetime.rs
@@ -0,0 +1,9 @@
+// This test is to ensure that the raw underscore lifetime won't emit two duplicate errors.
+// See issue #143152
+
+//@ edition: 2021
+
+fn f<'r#_>(){}
+//~^ ERROR `_` cannot be a raw lifetime
+
+fn main() {}
diff --git a/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr b/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr
new file mode 100644
index 00000000000..bdb357a47f4
--- /dev/null
+++ b/tests/ui/underscore-lifetime/raw-underscore-lifetime.stderr
@@ -0,0 +1,8 @@
+error: `_` cannot be a raw lifetime
+  --> $DIR/raw-underscore-lifetime.rs:6:6
+   |
+LL | fn f<'r#_>(){}
+   |      ^^^^
+
+error: aborting due to 1 previous error
+
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
+
diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs
new file mode 100644
index 00000000000..3749deb7627
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs
@@ -0,0 +1,25 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+#[stable(feature = "a", since = "1.1.1" )]
+pub trait Foo {
+    #[stable(feature = "a", since = "1.1.1" )]
+    fn foo();
+}
+#[stable(feature = "a", since = "1.1.1" )]
+pub struct Bar;
+#[stable(feature = "a", since = "1.1.1" )]
+pub struct Moo;
+
+#[unstable_feature_bound(feat_bar)]
+#[unstable(feature = "feat_bar", issue = "none" )]
+impl Foo for Bar {
+    fn foo() {}
+}
+
+#[unstable_feature_bound(feat_moo)]
+#[unstable(feature = "feat_moo", issue = "none" )]
+impl Foo for Moo {
+    fn foo() {}
+}
diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs
new file mode 100644
index 00000000000..8c0d14a1bab
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs
@@ -0,0 +1,19 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+/// Aux crate for unstable impl codegen test.
+
+#[stable(feature = "a", since = "1.1.1" )]
+pub trait Trait {
+    #[stable(feature = "a", since = "1.1.1" )]
+    fn method(&self);
+}
+
+#[unstable_feature_bound(foo)]
+#[unstable(feature = "foo", issue = "none" )]
+impl<T> Trait for T {
+    fn method(&self) {
+        println!("hi");
+    }
+}
diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs
new file mode 100644
index 00000000000..1b0e2b2eec3
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs
@@ -0,0 +1,13 @@
+//@ aux-build:unstable_impl_codegen_aux1.rs
+#![feature(foo)]
+
+extern crate unstable_impl_codegen_aux1 as aux;
+use aux::Trait;
+
+/// Upstream crate for unstable impl codegen test
+/// that depends on aux crate in
+/// unstable_impl_codegen_aux1.rs
+
+pub fn foo<T>(a: T) {
+    a.method();
+}
diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs
new file mode 100644
index 00000000000..2e055101216
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs
@@ -0,0 +1,11 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+#[stable(feature = "a", since = "1.1.1" )]
+pub trait Trait {}
+
+#[unstable_feature_bound(foo)]
+#[unstable(feature = "foo", issue = "none" )]
+impl <T> Trait for T {}
diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs
new file mode 100644
index 00000000000..3a433007b5d
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs
@@ -0,0 +1,20 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+#[stable(feature = "a", since = "1.1.1" )]
+pub trait Trait {
+    #[stable(feature = "a", since = "1.1.1" )]
+    fn foo(&self) {}
+}
+
+#[stable(feature = "a", since = "1.1.1" )]
+impl Trait for Vec<u32> {
+    fn foo(&self) {}
+}
+
+#[unstable_feature_bound(bar)]
+#[unstable(feature = "bar", issue = "none" )]
+impl Trait for Vec<u64> {
+    fn foo(&self) {}
+}
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs
new file mode 100644
index 00000000000..99501893ae0
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs
@@ -0,0 +1,35 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+/// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name,
+/// the error should not be thrown as it can effectively mark an impl as unstable.
+///
+/// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)]
+/// an error should still be thrown because that feature will not be unstable.
+
+#[stable(feature = "a", since = "1.1.1")]
+trait Moo {}
+#[stable(feature = "a", since = "1.1.1")]
+trait Foo {}
+#[stable(feature = "a", since = "1.1.1")]
+trait Boo {}
+#[stable(feature = "a", since = "1.1.1")]
+pub struct Bar;
+
+
+#[unstable(feature = "feat_moo", issue = "none")]
+#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect
+impl Moo for Bar {}
+
+#[unstable(feature = "feat_foo", issue = "none")]
+#[unstable_feature_bound(feat_foo)]
+impl Foo for Bar {}
+
+
+#[unstable(feature = "feat_foo", issue = "none")]
+#[unstable_feature_bound(feat_foo, feat_bar)]
+impl Boo for Bar {}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr
new file mode 100644
index 00000000000..4c8af2bbe56
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr
@@ -0,0 +1,11 @@
+error: an `#[unstable]` annotation here has no effect
+  --> $DIR/unstable-feature-bound-no-effect.rs:22:1
+   |
+LL | #[unstable(feature = "feat_moo", issue = "none")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
+   = note: `#[deny(ineffective_unstable_trait_impl)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs
new file mode 100644
index 00000000000..798c2d8562c
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs
@@ -0,0 +1,12 @@
+//@ aux-build:unstable_feature.rs
+extern crate unstable_feature;
+use unstable_feature::{Foo, Bar, Moo};
+
+// FIXME: both `feat_bar` and `feat_moo` are needed to pass this test,
+// but the diagnostic only will point out `feat_bar`.
+
+fn main() {
+    Bar::foo();
+    //~^ ERROR: use of unstable library feature `feat_bar` [E0658]
+    Moo::foo();
+}
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr
new file mode 100644
index 00000000000..673d10ce2ad
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr
@@ -0,0 +1,13 @@
+error[E0658]: use of unstable library feature `feat_bar`
+  --> $DIR/unstable-feature-bound-two-error.rs:9:5
+   |
+LL |     Bar::foo();
+   |     ^^^
+   |
+   = help: add `#![feature(feat_bar)]` 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: required for `Bar` to implement `Foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr
new file mode 100644
index 00000000000..ce8d7358cfc
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr
@@ -0,0 +1,13 @@
+error[E0658]: use of unstable library feature `feat_moo`
+  --> $DIR/unstable-feature-cross-crate-exact-symbol.rs:16:5
+   |
+LL |     Moo::foo();
+   |     ^^^
+   |
+   = help: add `#![feature(feat_moo)]` 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: required for `Moo` to implement `Foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs
new file mode 100644
index 00000000000..a427bb8eb7e
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs
@@ -0,0 +1,18 @@
+//@ aux-build:unstable_feature.rs
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![cfg_attr(pass, feature(feat_bar, feat_moo))]
+#![cfg_attr(fail, feature(feat_bar))]
+
+extern crate unstable_feature;
+use unstable_feature::{Foo, Bar, Moo};
+
+/// To use impls gated by both `feat_foo` and `feat_moo`,
+/// both features must be enabled.
+
+fn main() {
+    Bar::foo();
+    Moo::foo();
+    //[fail]~^ ERROR:use of unstable library feature `feat_moo` [E0658]
+}
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs
new file mode 100644
index 00000000000..5b09c898a08
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs
@@ -0,0 +1,11 @@
+//@ aux-build:unstable_feature.rs
+//@ check-pass
+#![feature(feat_bar, feat_moo)]
+extern crate unstable_feature;
+use unstable_feature::{Foo, Bar};
+
+/// Bar::foo() should still be usable even if we enable multiple feature.
+
+fn main() {
+    Bar::foo();
+}
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr
new file mode 100644
index 00000000000..87a2ad41fc1
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr
@@ -0,0 +1,13 @@
+error[E0658]: use of unstable library feature `feat_bar`
+  --> $DIR/unstable-feature-cross-crate-require-bound.rs:12:5
+   |
+LL |     Bar::foo();
+   |     ^^^
+   |
+   = help: add `#![feature(feat_bar)]` 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: required for `Bar` to implement `Foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs
new file mode 100644
index 00000000000..8be214b5324
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs
@@ -0,0 +1,14 @@
+//@ aux-build:unstable_feature.rs
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![cfg_attr(pass, feature(feat_bar))]
+extern crate unstable_feature;
+use unstable_feature::{Foo, Bar};
+
+/// #[feature(..)] is required to use unstable impl.
+
+fn main() {
+    Bar::foo();
+    //[fail]~^ ERROR: use of unstable library feature `feat_bar` [E0658]
+}
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr
new file mode 100644
index 00000000000..b8cb63ec65f
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr
@@ -0,0 +1,17 @@
+error: unstable feature `feat_moo` is used without being enabled.
+  --> $DIR/unstable-feature-exact-symbol.rs:37:5
+   |
+LL |     Bar::moo();
+   |     ^^^
+   |
+   = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_moo)]`
+note: required for `Bar` to implement `Moo`
+  --> $DIR/unstable-feature-exact-symbol.rs:29:6
+   |
+LL | #[unstable_feature_bound(feat_moo)]
+   | ----------------------------------- unsatisfied trait bound introduced here
+LL | impl Moo for Bar {
+   |      ^^^     ^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs
new file mode 100644
index 00000000000..2de9e6a857e
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs
@@ -0,0 +1,42 @@
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![unstable(feature = "feat_foo", issue = "none" )]
+
+/// In staged-api crate, impl that is marked as unstable with
+/// feature name `feat_moo` should not be accessible
+/// if only `feat_foo` is enabled.
+
+pub trait Foo {
+    fn foo();
+}
+
+pub trait Moo {
+    fn moo();
+}
+
+pub struct Bar;
+
+#[unstable_feature_bound(feat_foo)]
+impl Foo for Bar {
+    fn foo() {}
+}
+
+#[unstable_feature_bound(feat_moo)]
+impl Moo for Bar {
+    fn moo() {}
+}
+
+#[cfg_attr(fail, unstable_feature_bound(feat_foo))]
+#[cfg_attr(pass, unstable_feature_bound(feat_foo, feat_moo))]
+fn bar() {
+    Bar::foo();
+    Bar::moo();
+    //[fail]~^ ERROR  unstable feature `feat_moo` is used without being enabled.
+
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr
new file mode 100644
index 00000000000..db9759b4cc3
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr
@@ -0,0 +1,22 @@
+error: unstable feature `feat_foo` is used without being enabled.
+  --> $DIR/unstable-impl-assoc-type.rs:23:16
+   |
+LL |   type Assoc = Self;
+   |                ^^^^
+   |
+   = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]`
+note: required for `Foo` to implement `Bar`
+  --> $DIR/unstable-impl-assoc-type.rs:19:6
+   |
+LL | #[unstable_feature_bound(feat_foo)]
+   | ----------------------------------- unsatisfied trait bound introduced here
+LL | impl Bar for Foo {}
+   |      ^^^     ^^^
+note: required by a bound in `Trait::Assoc`
+  --> $DIR/unstable-impl-assoc-type.rs:13:17
+   |
+LL |     type Assoc: Bar;
+   |                 ^^^ required by this bound in `Trait::Assoc`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs
new file mode 100644
index 00000000000..e31dc688dfa
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs
@@ -0,0 +1,28 @@
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![unstable(feature = "feat_foo", issue = "none" )]
+
+/// Test that you can't leak unstable impls through item bounds on associated types.
+
+trait Bar {}
+
+trait Trait {
+    type Assoc: Bar;
+}
+
+struct Foo;
+
+#[unstable_feature_bound(feat_foo)]
+impl Bar for Foo {}
+
+#[cfg_attr(pass, unstable_feature_bound(feat_foo))]
+impl Trait for Foo {
+  type Assoc = Self;
+  //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled.
+
+}
+
+fn main(){}
diff --git a/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr
new file mode 100644
index 00000000000..d56072362fe
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr
@@ -0,0 +1,17 @@
+error: unstable feature `feat_foo` is used without being enabled.
+  --> $DIR/unstable-impl-cannot-use-feature.rs:26:5
+   |
+LL |     Bar::foo();
+   |     ^^^
+   |
+   = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]`
+note: required for `Bar` to implement `Foo`
+  --> $DIR/unstable-impl-cannot-use-feature.rs:20:6
+   |
+LL | #[unstable_feature_bound(feat_foo)]
+   | ----------------------------------- unsatisfied trait bound introduced here
+LL | impl Foo for Bar {
+   |      ^^^     ^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs
new file mode 100644
index 00000000000..0da618445fd
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs
@@ -0,0 +1,30 @@
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![unstable(feature = "feat_foo", issue = "none" )]
+
+#![cfg_attr(fail, feature(feat_foo))]
+
+/// In staged-api crate, using an unstable impl requires
+/// #[unstable_feature_bound(..)], not  #[feature(..)].
+
+pub trait Foo {
+    fn foo();
+}
+pub struct Bar;
+
+#[unstable_feature_bound(feat_foo)]
+impl Foo for Bar {
+    fn foo() {}
+}
+
+#[cfg_attr(pass, unstable_feature_bound(feat_foo))]
+fn bar() {
+    Bar::foo();
+    //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled.
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs b/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs
new file mode 100644
index 00000000000..c9a9029b0a0
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs
@@ -0,0 +1,27 @@
+//@ check-pass
+
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![unstable(feature = "feat_foo", issue = "none" )]
+
+/// In staged-api crate, if feat_foo is only needed to use an impl,
+/// having both `feat_foo` and `feat_bar` will still make it pass.
+
+pub trait Foo {
+    fn foo();
+}
+pub struct Bar;
+
+// Annotate the impl as unstable.
+#[unstable_feature_bound(feat_foo)]
+impl Foo for Bar {
+    fn foo() {}
+}
+
+#[unstable_feature_bound(feat_foo, feat_bar)]
+fn bar() {
+    Bar::foo();
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr
new file mode 100644
index 00000000000..f8354256828
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr
@@ -0,0 +1,17 @@
+error: unstable feature `feat_bar` is used without being enabled.
+  --> $DIR/unstable_feature_bound_free_fn.rs:36:5
+   |
+LL |     bar();
+   |     ^^^^^
+   |
+   = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]`
+note: required by a bound in `bar`
+  --> $DIR/unstable_feature_bound_free_fn.rs:29:1
+   |
+LL | #[unstable_feature_bound(feat_bar)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `bar`
+LL | fn bar() {
+   |    --- required by a bound in this function
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs
new file mode 100644
index 00000000000..30e2ab3d65e
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs
@@ -0,0 +1,40 @@
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+/// When a free function with #[unstable_feature_bound(feat_bar)] is called by another
+/// free function, that function should be annotated with
+/// #[unstable_feature_bound(feat_bar)] too.
+
+#[stable(feature = "a", since = "1.1.1")]
+trait Foo {
+    #[stable(feature = "a", since = "1.1.1")]
+    fn foo() {
+    }
+}
+#[stable(feature = "a", since = "1.1.1")]
+pub struct Bar;
+
+#[unstable_feature_bound(feat_bar)]
+#[unstable(feature = "feat_bar", issue = "none" )]
+impl Foo for Bar {
+    fn foo() {}
+}
+
+
+#[unstable_feature_bound(feat_bar)]
+fn bar() {
+    Bar::foo();
+}
+
+#[cfg_attr(pass, unstable_feature_bound(feat_bar))]
+fn bar2() {
+    bar();
+    //[fail]~^ERROR unstable feature `feat_bar` is used without being enabled.
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs
new file mode 100644
index 00000000000..1a9652c1023
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs
@@ -0,0 +1,14 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+// Lint against the usage of both #[unstable_feature_bound] and #[stable] on the
+// same item.
+
+#[stable(feature = "a", since = "1.1.1")]
+#[unstable_feature_bound(feat_bar)]
+fn bar() {}
+//~^ ERROR Item annotated with `#[unstable_feature_bound]` should not be stable
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr
new file mode 100644
index 00000000000..9cb6a181bef
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr
@@ -0,0 +1,10 @@
+error: Item annotated with `#[unstable_feature_bound]` should not be stable
+  --> $DIR/unstable_feature_bound_incompatible_stability.rs:11:1
+   |
+LL | fn bar() {}
+   | ^^^^^^^^^^^
+   |
+   = help: If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs
new file mode 100644
index 00000000000..3d6b52ba517
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs
@@ -0,0 +1,36 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![allow(dead_code)]
+#![unstable(feature = "feat_bar", issue = "none" )]
+
+/// Test the behaviour of multiple unstable_feature_bound attribute.
+
+trait Foo {
+    fn foo();
+}
+struct Bar;
+
+#[unstable_feature_bound(feat_bar, feat_koo)]
+#[unstable_feature_bound(feat_foo, feat_moo)]
+impl Foo for Bar {
+    fn foo(){}
+}
+
+#[unstable_feature_bound(feat_bar, feat_koo)]
+#[unstable_feature_bound(feat_foo, feat_moo)]
+fn moo() {
+    Bar::foo();
+}
+
+#[unstable_feature_bound(feat_bar, feat_koo, feat_foo, feat_moo)]
+fn koo() {
+    Bar::foo();
+}
+
+#[unstable_feature_bound(feat_koo, feat_foo, feat_moo)]
+fn boo() {
+    Bar::foo();
+    //~^ ERROR: unstable feature `feat_bar` is used without being enabled.
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr
new file mode 100644
index 00000000000..936c70c1979
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr
@@ -0,0 +1,18 @@
+error: unstable feature `feat_bar` is used without being enabled.
+  --> $DIR/unstable_feature_bound_multi_attr.rs:32:5
+   |
+LL |     Bar::foo();
+   |     ^^^
+   |
+   = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]`
+note: required for `Bar` to implement `Foo`
+  --> $DIR/unstable_feature_bound_multi_attr.rs:15:6
+   |
+LL | #[unstable_feature_bound(feat_bar, feat_koo)]
+   | --------------------------------------------- unsatisfied trait bound introduced here
+LL | #[unstable_feature_bound(feat_foo, feat_moo)]
+LL | impl Foo for Bar {
+   |      ^^^     ^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs
new file mode 100644
index 00000000000..51e388f7dd3
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs
@@ -0,0 +1,13 @@
+/// Unstable feature bound can only be used only when
+/// #[feature(staged_api)] is enabled.
+
+pub trait Foo {
+}
+pub struct Bar;
+
+#[unstable_feature_bound(feat_bar)]
+//~^ ERROR: stability attributes may not be used outside of the standard library
+impl Foo for Bar {
+}
+
+fn main(){}
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr
new file mode 100644
index 00000000000..35ab89e6ad9
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr
@@ -0,0 +1,9 @@
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/unstable_feature_bound_staged_api.rs:8:1
+   |
+LL | #[unstable_feature_bound(feat_bar)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0734`.
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs b/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs
new file mode 100644
index 00000000000..285a64d2250
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs
@@ -0,0 +1,13 @@
+//@ aux-build:unstable_impl_codegen_aux2.rs
+//@ run-pass
+
+/// Downstream crate for unstable impl codegen test
+/// that depends on upstream crate in
+/// unstable_impl_codegen_aux2.rs
+
+extern crate unstable_impl_codegen_aux2 as aux;
+use aux::foo;
+
+fn main() {
+    foo(1_u8);
+}
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr
new file mode 100644
index 00000000000..c3147558b03
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy`
+  --> $DIR/unstable_impl_coherence.rs:14:1
+   |
+LL | impl aux::Trait for LocalTy {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `unstable_impl_coherence_aux`:
+           - impl<T> Trait for T
+             where unstable feature: `foo`;
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr
new file mode 100644
index 00000000000..c3147558b03
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy`
+  --> $DIR/unstable_impl_coherence.rs:14:1
+   |
+LL | impl aux::Trait for LocalTy {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `unstable_impl_coherence_aux`:
+           - impl<T> Trait for T
+             where unstable feature: `foo`;
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs b/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs
new file mode 100644
index 00000000000..22100f85f71
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs
@@ -0,0 +1,17 @@
+//@ aux-build:unstable_impl_coherence_aux.rs
+//@ revisions: enabled disabled
+
+#![cfg_attr(enabled, feature(foo))]
+extern crate unstable_impl_coherence_aux as aux;
+use aux::Trait;
+
+/// Coherence test for unstable impl.
+/// No matter feature `foo` is enabled or not, the impl
+/// for aux::Trait will be rejected by coherence checking.
+
+struct LocalTy;
+
+impl aux::Trait for LocalTy {}
+//~^ ERROR: conflicting implementations of trait `Trait` for type `LocalTy`
+
+fn main(){}
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs
new file mode 100644
index 00000000000..acf521d3130
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs
@@ -0,0 +1,15 @@
+//@ aux-build:unstable_impl_method_selection_aux.rs
+
+extern crate unstable_impl_method_selection_aux as aux;
+use aux::Trait;
+
+// The test below should not infer the type based on the fact
+// that `impl Trait for Vec<u64>` is unstable. This would cause breakage
+// in downstream crate once `impl Trait for Vec<u64>` is stabilised.
+
+fn bar() {
+    vec![].foo();
+    //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr
new file mode 100644
index 00000000000..c2bb10f043b
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr
@@ -0,0 +1,14 @@
+error[E0283]: type annotations needed
+  --> $DIR/unstable_impl_method_selection.rs:11:12
+   |
+LL |     vec![].foo();
+   |            ^^^ cannot infer type for struct `Vec<_>`
+   |
+   = note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_method_selection_aux` crate:
+           - impl Trait for Vec<u32>;
+           - impl Trait for Vec<u64>
+             where unstable feature: `bar`;
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs
new file mode 100644
index 00000000000..5f3095430a8
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs
@@ -0,0 +1,23 @@
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+/// FIXME(tiif): we haven't allowed marking trait and impl method as
+/// unstable yet, but it should be possible.
+
+#[stable(feature = "a", since = "1.1.1" )]
+pub trait Trait {
+    #[unstable(feature = "feat", issue = "none" )]
+    #[unstable_feature_bound(foo)]
+    //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait
+    fn foo();
+}
+
+#[stable(feature = "a", since = "1.1.1" )]
+impl Trait for u8 {
+    #[unstable_feature_bound(foo)]
+    //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait
+    fn foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr
new file mode 100644
index 00000000000..fa1c39db259
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr
@@ -0,0 +1,20 @@
+error: attribute should be applied to `impl` or free function outside of any `impl` or trait
+  --> $DIR/unstable_inherent_method.rs:11:5
+   |
+LL |     #[unstable_feature_bound(foo)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     fn foo();
+   |     --------- not an `impl` or free function
+
+error: attribute should be applied to `impl` or free function outside of any `impl` or trait
+  --> $DIR/unstable_inherent_method.rs:18:5
+   |
+LL |     #[unstable_feature_bound(foo)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     fn foo() {}
+   |     ----------- not an `impl` or free function
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/where-clauses/ignore-err-clauses.rs b/tests/ui/where-clauses/ignore-err-clauses.rs
index 428ebf4b408..6f21e5ccbaa 100644
--- a/tests/ui/where-clauses/ignore-err-clauses.rs
+++ b/tests/ui/where-clauses/ignore-err-clauses.rs
@@ -1,13 +1,13 @@
 use std::ops::Add;
 
 fn dbl<T>(x: T) -> <T as Add>::Output
-//~^ ERROR type annotations needed
 where
     T: Copy + Add,
     UUU: Copy,
     //~^ ERROR cannot find type `UUU` in this scope
 {
     x + x
+    //~^ ERROR use of moved value: `x`
 }
 
 fn main() {
diff --git a/tests/ui/where-clauses/ignore-err-clauses.stderr b/tests/ui/where-clauses/ignore-err-clauses.stderr
index fbf1b99334f..9c76c1c6a04 100644
--- a/tests/ui/where-clauses/ignore-err-clauses.stderr
+++ b/tests/ui/where-clauses/ignore-err-clauses.stderr
@@ -1,16 +1,33 @@
 error[E0412]: cannot find type `UUU` in this scope
-  --> $DIR/ignore-err-clauses.rs:7:5
+  --> $DIR/ignore-err-clauses.rs:6:5
    |
 LL |     UUU: Copy,
    |     ^^^ not found in this scope
 
-error[E0282]: type annotations needed
-  --> $DIR/ignore-err-clauses.rs:3:14
+error[E0382]: use of moved value: `x`
+  --> $DIR/ignore-err-clauses.rs:9:9
    |
 LL | fn dbl<T>(x: T) -> <T as Add>::Output
-   |              ^ cannot infer type for type parameter `T`
+   |           - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+...
+LL |     x + x
+   |     ----^
+   |     |   |
+   |     |   value used here after move
+   |     `x` moved due to usage in operator
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/ignore-err-clauses.rs:3:8
+   |
+LL | fn dbl<T>(x: T) -> <T as Add>::Output
+   |        ^ consider constraining this type parameter with `Clone`
+...
+LL |     x + x
+   |     - you could clone this value
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0412.
-For more information about an error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0382, E0412.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/triagebot.toml b/triagebot.toml
index 2f8114aeb3b..61d8a814c89 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -471,6 +471,7 @@ trigger_files = [
 
 [autolabel."T-infra"]
 trigger_files = [
+    ".github/workflows",
     "src/ci",
     "src/tools/bump-stage0",
     "src/tools/cargotest",
@@ -598,6 +599,12 @@ trigger_files = [
     "src/tools/clippy",
 ]
 
+[autolabel."A-CI"]
+trigger_files = [
+    ".github/workflows",
+    "src/ci",
+]
+
 # ------------------------------------------------------------------------------
 # Prioritization and team nominations
 # ------------------------------------------------------------------------------
@@ -1316,6 +1323,7 @@ infra-ci = [
     "@Kobzol",
     "@marcoieni",
     "@jdno",
+    "@jieyouxu",
 ]
 rustdoc = [
     "@GuillaumeGomez",