summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--RELEASES.md7
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs18
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs276
-rw-r--r--compiler/rustc_ast/src/visit.rs146
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml1
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl6
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs70
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs110
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs13
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs1
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs129
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs161
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs68
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/lib.rs108
-rw-r--r--compiler/rustc_borrowck/src/nll.rs46
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs1
-rw-r--r--compiler/rustc_borrowck/src/polonius/mod.rs15
-rw-r--r--compiler/rustc_borrowck/src/region_infer/dump_mir.rs3
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs82
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs39
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs58
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs2
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs15
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs143
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs62
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh5
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs23
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs18
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs16
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs18
-rw-r--r--compiler/rustc_codegen_gcc/src/int.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/mono_item.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs65
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs19
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs31
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs36
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs45
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs20
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs47
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs23
-rw-r--r--compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs24
-rw-r--r--compiler/rustc_const_eval/src/check_consts/resolver.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs49
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs13
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs30
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs78
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs21
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs13
-rw-r--r--compiler/rustc_const_eval/src/lib.rs7
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs6
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs10
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs13
-rw-r--r--compiler/rustc_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_data_structures/src/unord.rs5
-rw-r--r--compiler/rustc_data_structures/src/vec_cache.rs324
-rw-r--r--compiler/rustc_data_structures/src/vec_cache/tests.rs95
-rw-r--r--compiler/rustc_driver_impl/messages.ftl2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs117
-rw-r--r--compiler/rustc_driver_impl/src/session_diagnostics.rs8
-rw-r--r--compiler/rustc_expand/src/expand.rs6
-rw-r--r--compiler/rustc_expand/src/placeholders.rs4
-rw-r--r--compiler/rustc_feature/Cargo.toml2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs7
-rw-r--r--compiler/rustc_feature/src/lib.rs19
-rw-r--r--compiler/rustc_feature/src/tests.rs12
-rw-r--r--compiler/rustc_feature/src/unstable.rs54
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl5
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs102
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs89
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs33
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs51
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs167
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs33
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs55
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs15
-rw-r--r--compiler/rustc_index/src/bit_set.rs140
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs46
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs27
-rw-r--r--compiler/rustc_interface/src/passes.rs29
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lexer/src/lib.rs106
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/builtin.rs20
-rw-r--r--compiler/rustc_lint/src/context.rs14
-rw-r--r--compiler/rustc_lint/src/dangling.rs27
-rw-r--r--compiler/rustc_lint/src/drop_forget_useless.rs2
-rw-r--r--compiler/rustc_lint/src/early.rs40
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs4
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs30
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs2
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs12
-rw-r--r--compiler/rustc_lint/src/internal.rs5
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs22
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs16
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs4
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs2
-rw-r--r--compiler/rustc_lint/src/tail_expr_drop_order.rs305
-rw-r--r--compiler/rustc_lint/src/types.rs51
-rw-r--r--compiler/rustc_lint/src/unused.rs13
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs83
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs50
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/lint.rs18
-rw-r--r--compiler/rustc_middle/src/middle/region.rs5
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs29
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs61
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs15
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs14
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs45
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs24
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs35
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs4
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs37
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/query/erase.rs4
-rw-r--r--compiler/rustc_middle/src/query/keys.rs28
-rw-r--r--compiler/rustc_middle/src/query/mod.rs77
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs10
-rw-r--r--compiler/rustc_middle/src/thir.rs63
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs5
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs11
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs131
-rw-r--r--compiler/rustc_middle/src/ty/context.rs22
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs37
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs41
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs123
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs105
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs49
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs27
-rw-r--r--compiler/rustc_middle/src/ty/util.rs80
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs4
-rw-r--r--compiler/rustc_middle/src/util/call_kind.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs31
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs34
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs21
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs15
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs15
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs17
-rw-r--r--compiler/rustc_mir_build/src/build/misc.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs95
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs64
-rw-r--r--compiler/rustc_mir_build/src/errors.rs10
-rw-r--r--compiler/rustc_mir_build/src/lints.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs76
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs14
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs74
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs88
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs50
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs13
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs56
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs143
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs21
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs16
-rw-r--r--compiler/rustc_mir_transform/messages.ftl25
-rw-r--r--compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs9
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs31
-rw-r--r--compiler/rustc_mir_transform/src/cost_checker.rs10
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs1
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs58
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs3
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs6
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs5
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs22
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs33
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs52
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs15
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs12
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs15
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs31
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs11
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs20
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs701
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs56
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs6
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs1
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs22
-rw-r--r--compiler/rustc_mir_transform/src/remove_unneeded_drops.rs10
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs9
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs12
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs14
-rw-r--r--compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs8
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs18
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs8
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs4
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs14
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs6
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_enum_branching.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs56
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs183
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs5
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/abi_check.rs21
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/move_check.rs6
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs17
-rw-r--r--compiler/rustc_monomorphize/src/util.rs10
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs12
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs70
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs67
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs17
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs32
-rw-r--r--compiler/rustc_parse/src/errors.rs3
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs5
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs11
-rw-r--r--compiler/rustc_parse/src/parser/item.rs33
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs3
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs109
-rw-r--r--compiler/rustc_passes/src/abi_test.rs36
-rw-r--r--compiler/rustc_passes/src/check_attr.rs3
-rw-r--r--compiler/rustc_passes/src/dead.rs11
-rw-r--r--compiler/rustc_passes/src/input_stats.rs (renamed from compiler/rustc_passes/src/hir_stats.rs)9
-rw-r--r--compiler/rustc_passes/src/layout_test.rs37
-rw-r--r--compiler/rustc_passes/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs9
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs38
-rw-r--r--compiler/rustc_query_system/src/lib.rs1
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs94
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs12
-rw-r--r--compiler/rustc_resolve/src/ident.rs126
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs17
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs4
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs4
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs18
-rw-r--r--compiler/rustc_session/src/config.rs155
-rw-r--r--compiler/rustc_session/src/config/native_libs.rs192
-rw-r--r--compiler/rustc_session/src/config/native_libs/tests.rs50
-rw-r--r--compiler/rustc_session/src/options.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs8
-rw-r--r--compiler/rustc_smir/src/rustc_smir/builder.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs52
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs7
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs13
-rw-r--r--compiler/rustc_target/src/callconv/s390x.rs26
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs2
-rw-r--r--compiler/rustc_target/src/target_features.rs37
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs2
-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/suggestions.rs177
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs15
-rw-r--r--compiler/rustc_traits/src/codegen.rs9
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs6
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs8
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs4
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs38
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs17
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs58
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs44
-rw-r--r--compiler/rustc_ty_utils/src/layout/invariant.rs2
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs106
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs2
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs16
-rw-r--r--compiler/rustc_type_ir/src/interner.rs7
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs1
-rw-r--r--config.example.toml2
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/alloc/src/boxed.rs8
-rw-r--r--library/alloc/src/collections/btree/map.rs46
-rw-r--r--library/alloc/src/collections/vec_deque/iter.rs34
-rw-r--r--library/alloc/src/collections/vec_deque/iter_mut.rs107
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/alloc/src/vec/mod.rs2
-rw-r--r--library/core/src/cell.rs5
-rw-r--r--library/core/src/ffi/c_str.rs1
-rw-r--r--library/core/src/intrinsics/mod.rs169
-rw-r--r--library/core/src/lib.rs5
-rw-r--r--library/core/src/marker.rs12
-rw-r--r--library/core/src/mem/maybe_uninit.rs2
-rw-r--r--library/core/src/num/int_macros.rs2
-rw-r--r--library/core/src/num/uint_macros.rs2
-rw-r--r--library/core/src/panic.rs2
-rw-r--r--library/core/src/pin.rs6
-rw-r--r--library/core/src/ptr/const_ptr.rs8
-rw-r--r--library/core/src/ptr/mod.rs16
-rw-r--r--library/core/src/ptr/mut_ptr.rs6
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/core/src/slice/raw.rs4
-rw-r--r--library/core/src/str/mod.rs2
-rw-r--r--library/core/src/sync/atomic.rs6
-rw-r--r--library/core/src/ub_checks.rs16
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/collections/hash/map.rs40
-rw-r--r--library/std/src/fs.rs4
-rw-r--r--library/std/src/io/cursor.rs6
-rw-r--r--library/std/src/keyword_docs.rs6
-rw-r--r--library/std/src/sync/rwlock.rs74
-rw-r--r--library/std/src/sync/rwlock/tests.rs108
-rw-r--r--library/std/src/sys/pal/uefi/process.rs68
-rw-r--r--library/std/src/sys/sync/rwlock/futex.rs52
-rw-r--r--library/std/src/sys/sync/rwlock/no_threads.rs5
-rw-r--r--library/std/src/sys/sync/rwlock/queue.rs675
-rw-r--r--library/std/src/sys/sync/rwlock/solid.rs6
-rw-r--r--library/std/src/sys/sync/rwlock/teeos.rs6
-rw-r--r--library/std/src/thread/mod.rs34
-rw-r--r--library/std/src/thread/spawnhook.rs148
m---------library/stdarch0
-rw-r--r--library/test/src/lib.rs11
-rw-r--r--src/bootstrap/src/core/config/config.rs4
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile2
-rw-r--r--src/ci/github-actions/jobs.yml4
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md113
-rw-r--r--src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md83
-rw-r--r--src/doc/rustc/src/platform-support/wasm32-wasip2.md2
-rw-r--r--src/doc/rustdoc/src/command-line-arguments.md29
-rw-r--r--src/doc/rustdoc/src/unstable-features.md33
-rw-r--r--src/doc/unstable-book/src/language-features/asm-goto.md4
-rw-r--r--src/librustdoc/clean/auto_trait.rs12
-rw-r--r--src/librustdoc/clean/mod.rs23
-rw-r--r--src/librustdoc/clean/types.rs6
-rw-r--r--src/librustdoc/clean/utils.rs5
-rw-r--r--src/librustdoc/core.rs9
-rw-r--r--src/librustdoc/html/highlight.rs7
-rw-r--r--src/librustdoc/html/render/span_map.rs23
-rw-r--r--src/librustdoc/html/render/type_layout.rs6
-rw-r--r--src/librustdoc/html/static/js/search.js85
m---------src/llvm-project0
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_frames.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/zst_offset.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/erasing_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/uninhabited_references.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs56
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs56
-rw-r--r--src/tools/miri/miri-script/Cargo.lock10
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs8
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs12
-rw-r--r--src/tools/miri/src/eval.rs14
-rw-r--r--src/tools/miri/src/helpers.rs4
-rw-r--r--src/tools/miri/src/machine.rs7
-rw-r--r--src/tools/miri/tests/pass/shims/time-with-isolation.stdout2
-rw-r--r--src/tools/run-make-support/src/external_deps/c_build.rs2
-rw-r--r--src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs (renamed from src/tools/run-make-support/src/external_deps/cc.rs)98
-rw-r--r--src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs97
-rw-r--r--src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs66
-rw-r--r--src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs7
-rw-r--r--src/tools/run-make-support/src/external_deps/mod.rs2
-rw-r--r--src/tools/run-make-support/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/Cargo.lock8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs29
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs10
-rw-r--r--src/tools/rustfmt/src/items.rs11
-rw-r--r--src/tools/rustfmt/src/visitor.rs17
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs34
-rw-r--r--tests/assembly/s390x-vector-abi.rs322
-rw-r--r--tests/codegen/checked_math.rs2
-rw-r--r--tests/codegen/intrinsics/cold_path.rs13
-rw-r--r--tests/codegen/intrinsics/likely.rs37
-rw-r--r--tests/codegen/intrinsics/likely_assert.rs17
-rw-r--r--tests/codegen/intrinsics/unlikely.rs35
-rw-r--r--tests/crashes/113280.rs16
-rw-r--r--tests/crashes/123077-2.rs12
-rw-r--r--tests/crashes/127676.rs8
-rw-r--r--tests/crashes/129150.rs7
-rw-r--r--tests/crashes/130687.rs4
-rw-r--r--tests/crashes/131535.rs4
-rw-r--r--tests/crashes/131637.rs7
-rw-r--r--tests/crashes/132530.rs9
-rw-r--r--tests/crashes/132985.rs17
-rw-r--r--tests/crashes/auxiliary/aux132985.rs6
-rw-r--r--tests/debuginfo/numeric-types.rs64
-rw-r--r--tests/debuginfo/range-types.rs20
-rw-r--r--tests/debuginfo/unit-type.rs11
-rw-r--r--tests/incremental/hygiene/load_cached_hygiene.rs2
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir23
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir23
-rw-r--r--tests/run-make/mte-ffi/rmake.rs17
-rw-r--r--tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs18
-rw-r--r--tests/run-make/unstable-feature-usage-metrics/lib.rs9
-rw-r--r--tests/run-make/unstable-feature-usage-metrics/rmake.rs87
-rw-r--r--tests/rustdoc-js-std/parser-errors.js8
-rw-r--r--tests/rustdoc-js-std/path-end-empty.js6
-rw-r--r--tests/rustdoc-js/trailing.js7
-rw-r--r--tests/rustdoc-js/trailing.rs3
-rw-r--r--tests/rustdoc/link-on-path-with-generics.rs14
-rw-r--r--tests/ui-fulldeps/stable-mir/check_intrinsics.rs6
-rw-r--r--tests/ui/asm/x86_64/goto-block-safe.rs23
-rw-r--r--tests/ui/asm/x86_64/goto-block-safe.stderr14
-rw-r--r--tests/ui/auxiliary/pub-and-stability.rs4
-rw-r--r--tests/ui/bootstrap/rustc_bootstap.force_stable.stderr10
-rw-r--r--tests/ui/bootstrap/rustc_bootstap.rs47
-rw-r--r--tests/ui/check-cfg/auxiliary/cfg_macro.rs11
-rw-r--r--tests/ui/check-cfg/report-in-external-macros.rs12
-rw-r--r--tests/ui/check-cfg/report-in-external-macros.stderr14
-rw-r--r--tests/ui/closures/2229_closure_analysis/bad-pattern.stderr13
-rw-r--r--tests/ui/closures/correct-args-on-call-suggestion.rs7
-rw-r--r--tests/ui/closures/correct-args-on-call-suggestion.stderr20
-rw-r--r--tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs18
-rw-r--r--tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr59
-rw-r--r--tests/ui/confuse-field-and-method/issue-18343.stderr2
-rw-r--r--tests/ui/confuse-field-and-method/issue-2392.stderr14
-rw-r--r--tests/ui/confuse-field-and-method/issue-32128.stderr2
-rw-r--r--tests/ui/confuse-field-and-method/issue-33784.stderr6
-rw-r--r--tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs6
-rw-r--r--tests/ui/const-generics/using-static-as-const-arg.rs7
-rw-r--r--tests/ui/const-generics/xcrate-const-ctor-b.rs15
-rw-r--r--tests/ui/consts/const-pattern-irrefutable.rs27
-rw-r--r--tests/ui/consts/const-pattern-irrefutable.stderr73
-rw-r--r--tests/ui/consts/const-ptr-is-null.rs1
-rw-r--r--tests/ui/consts/const-ptr-is-null.stderr2
-rw-r--r--tests/ui/consts/const-unstable-intrinsic.stderr2
-rw-r--r--tests/ui/consts/const_in_pattern/incomplete-slice.stderr12
-rw-r--r--tests/ui/consts/is_val_statically_known.rs2
-rw-r--r--tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs2
-rw-r--r--tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs12
-rw-r--r--tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr15
-rw-r--r--tests/ui/consts/ptr_is_null.rs1
-rw-r--r--tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs4124
-rw-r--r--tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs4122
-rw-r--r--tests/ui/delegation/unsupported.rs8
-rw-r--r--tests/ui/delegation/unsupported.stderr61
-rw-r--r--tests/ui/diagnostic_namespace/deny_malformed_attribute.rs2
-rw-r--r--tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs1
-rw-r--r--tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr36
-rw-r--r--tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs1
-rw-r--r--tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs1
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr54
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs (renamed from tests/ui/traits/custom-on-unimplemented-diagnostic.rs)2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr (renamed from tests/ui/traits/custom-on-unimplemented-diagnostic.stderr)8
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs4
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr74
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr54
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs1
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr14
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs1
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr12
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs1
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr14
-rw-r--r--tests/ui/diagnostic_namespace/suggest_typos.rs1
-rw-r--r--tests/ui/diagnostic_namespace/suggest_typos.stderr8
-rw-r--r--tests/ui/drop/lint-tail-expr-drop-order-gated.rs7
-rw-r--r--tests/ui/drop/lint-tail-expr-drop-order.rs215
-rw-r--r--tests/ui/drop/lint-tail-expr-drop-order.stderr327
-rw-r--r--tests/ui/dyn-star/async-block-dyn-star.rs9
-rw-r--r--tests/ui/dyn-star/async-block-dyn-star.stderr20
-rw-r--r--tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr11
-rw-r--r--tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr11
-rw-r--r--tests/ui/dyn-star/drop.rs7
-rw-r--r--tests/ui/dyn-star/enum-cast.rs7
-rw-r--r--tests/ui/dyn-star/error.rs2
-rw-r--r--tests/ui/dyn-star/error.stderr4
-rw-r--r--tests/ui/dyn-star/float-as-dyn-star.rs16
-rw-r--r--tests/ui/dyn-star/float-as-dyn-star.stderr21
-rw-r--r--tests/ui/dyn-star/upcast.stderr10
-rw-r--r--tests/ui/editions/never-type-fallback-breaking.e2021.fixed6
-rw-r--r--tests/ui/editions/never-type-fallback-breaking.e2021.stderr6
-rw-r--r--tests/ui/editions/never-type-fallback-breaking.rs6
-rw-r--r--tests/ui/explore-issue-38412.rs8
-rw-r--r--tests/ui/feature-gates/feature-gate-large-assignments.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-link-arg-attribute.in_attr.stderr (renamed from tests/ui/feature-gates/feature-gate-link-arg-attribute.stderr)2
-rw-r--r--tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-link-arg-attribute.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-min-generic-const-args.rs11
-rw-r--r--tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr11
-rw-r--r--tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_attr.stderr (renamed from tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr)2
-rw-r--r--tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs6
-rw-r--r--tests/ui/generics/generics-on-self-mod-segment.rs18
-rw-r--r--tests/ui/generics/generics-on-self-mod-segment.stderr32
-rw-r--r--tests/ui/impl-trait/in-trait/refine-captures.rs36
-rw-r--r--tests/ui/impl-trait/in-trait/refine-captures.stderr52
-rw-r--r--tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs20
-rw-r--r--tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs29
-rw-r--r--tests/ui/impl-trait/precise-capturing/external-macro.rs26
-rw-r--r--tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed5
-rw-r--r--tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs5
-rw-r--r--tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr51
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.rs6
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.stderr6
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs31
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr82
-rw-r--r--tests/ui/issues/issue-39848.stderr6
-rw-r--r--tests/ui/let-else/let-else-if.stderr2
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.rs7
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.stderr54
-rw-r--r--tests/ui/lint/issue-104392.stderr2
-rw-r--r--tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed8
-rw-r--r--tests/ui/lint/unused/issue-54538-unused-parens-lint.rs8
-rw-r--r--tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr69
-rw-r--r--tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed32
-rw-r--r--tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs32
-rw-r--r--tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr43
-rw-r--r--tests/ui/lint/unused_parens_json_suggestion.fixed2
-rw-r--r--tests/ui/lint/unused_parens_json_suggestion.rs2
-rw-r--r--tests/ui/lint/unused_parens_json_suggestion.stderr2
-rw-r--r--tests/ui/lint/unused_parens_remove_json_suggestion.fixed2
-rw-r--r--tests/ui/lint/unused_parens_remove_json_suggestion.rs2
-rw-r--r--tests/ui/lint/unused_parens_remove_json_suggestion.stderr18
-rw-r--r--tests/ui/match/intended-binding-pattern-is-const.rs10
-rw-r--r--tests/ui/match/intended-binding-pattern-is-const.stderr27
-rw-r--r--tests/ui/mir/issue-112269.stderr24
-rw-r--r--tests/ui/missing/missing-block-hint.stderr2
-rw-r--r--tests/ui/moves/moved-value-on-as-ref-arg.fixed4
-rw-r--r--tests/ui/moves/moved-value-on-as-ref-arg.rs4
-rw-r--r--tests/ui/moves/region-var-in-moved-ty-issue-133118.rs25
-rw-r--r--tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr21
-rw-r--r--tests/ui/native-library-link-flags/modifiers-bad.blank.stderr2
-rw-r--r--tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr2
-rw-r--r--tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr2
-rw-r--r--tests/ui/native-library-link-flags/modifiers-bad.rs11
-rw-r--r--tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr2
-rw-r--r--tests/ui/never_type/defaulted-never-note.nofallback.stderr2
-rw-r--r--tests/ui/never_type/defaulted-never-note.rs2
-rw-r--r--tests/ui/never_type/dependency-on-fallback-to-unit.rs4
-rw-r--r--tests/ui/never_type/dependency-on-fallback-to-unit.stderr4
-rw-r--r--tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr4
-rw-r--r--tests/ui/never_type/diverging-fallback-control-flow.rs4
-rw-r--r--tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr2
-rw-r--r--tests/ui/never_type/diverging-fallback-no-leak.rs2
-rw-r--r--tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr2
-rw-r--r--tests/ui/never_type/diverging-fallback-unconstrained-return.rs2
-rw-r--r--tests/ui/never_type/fallback-closure-ret.nofallback.stderr2
-rw-r--r--tests/ui/never_type/fallback-closure-ret.rs2
-rw-r--r--tests/ui/never_type/impl_trait_fallback.rs2
-rw-r--r--tests/ui/never_type/impl_trait_fallback.stderr2
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr20
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr20
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs20
-rw-r--r--tests/ui/parser/bad-if-statements.stderr4
-rw-r--r--tests/ui/parser/block-no-opening-brace.stderr6
-rw-r--r--tests/ui/parser/closure-return-syntax.stderr2
-rw-r--r--tests/ui/parser/else-no-if.stderr18
-rw-r--r--tests/ui/parser/label-after-block-like.stderr14
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed39
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs39
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr57
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs57
-rw-r--r--tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr101
-rw-r--r--tests/ui/parser/suggest-const-for-global-var.stderr7
-rw-r--r--tests/ui/parser/suggest-static-for-global-var-mut.rs5
-rw-r--r--tests/ui/parser/suggest-static-for-global-var-mut.stderr11
-rw-r--r--tests/ui/parser/unnecessary-let.fixed13
-rw-r--r--tests/ui/parser/unnecessary-let.rs4
-rw-r--r--tests/ui/parser/unnecessary-let.stderr24
-rw-r--r--tests/ui/pattern/usefulness/conflicting_bindings.rs2
-rw-r--r--tests/ui/pattern/usefulness/conflicting_bindings.stderr18
-rw-r--r--tests/ui/pattern/usefulness/match-arm-statics-2.stderr12
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr72
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs11
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs25
-rw-r--r--tests/ui/simd-abi-checks-s390x.rs174
-rw-r--r--tests/ui/simd-abi-checks-s390x.z10.stderr111
-rw-r--r--tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr111
-rw-r--r--tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr111
-rw-r--r--tests/ui/stats/input-stats.rs (renamed from tests/ui/stats/hir-stats.rs)6
-rw-r--r--tests/ui/stats/input-stats.stderr (renamed from tests/ui/stats/hir-stats.stderr)6
-rw-r--r--tests/ui/structs-enums/enum-rec/issue-17431-6.rs6
-rw-r--r--tests/ui/structs-enums/enum-rec/issue-17431-6.stderr14
-rw-r--r--tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr4
-rw-r--r--tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs2
-rw-r--r--tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr13
-rw-r--r--tests/ui/symbol-names/basic.rs2
-rw-r--r--tests/ui/symbol-names/impl1.rs2
-rw-r--r--tests/ui/symbol-names/issue-60925.rs2
-rw-r--r--tests/ui/thir-print/thir-flat-const-variant.stdout162
-rw-r--r--tests/ui/thir-print/thir-flat.stdout18
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout28
-rw-r--r--tests/ui/thir-print/thir-tree.stdout4
-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.stderr4
-rw-r--r--tests/ui/traits/const-traits/const-closure-parse-not-item.stderr10
-rw-r--r--tests/ui/traits/const-traits/const-fns-are-early-bound.rs90
-rw-r--r--tests/ui/traits/const-traits/const-opaque.no.stderr15
-rw-r--r--tests/ui/traits/const-traits/const-opaque.rs38
-rw-r--r--tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs1
-rw-r--r--tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr16
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs22
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-fn-fail.rs21
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr9
-rw-r--r--tests/ui/traits/const-traits/effects/minicore-works.rs6
-rw-r--r--tests/ui/traits/negative-bounds/on-unimplemented.rs2
-rw-r--r--tests/ui/traits/negative-bounds/on-unimplemented.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder.rs3
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr14
-rw-r--r--tests/ui/unsafe/unsafe-block-without-braces.stderr2
-rw-r--r--triagebot.toml31
753 files changed, 21219 insertions, 5822 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b98c4fd0642..51e21f6dc82 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -111,9 +111,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.17"
+version = "0.6.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -3270,6 +3270,7 @@ name = "rustc_ast_lowering"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
+ "rustc_ast_pretty",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
@@ -3684,6 +3685,8 @@ version = "0.0.0"
 dependencies = [
  "rustc_data_structures",
  "rustc_span",
+ "serde",
+ "serde_json",
 ]
 
 [[package]]
diff --git a/RELEASES.md b/RELEASES.md
index 40ddba6dbc5..54465621b73 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -670,13 +670,6 @@ Cargo
 - [Support `target.<triple>.rustdocflags` officially](https://github.com/rust-lang/cargo/pull/13197/)
 - [Stabilize global cache data tracking](https://github.com/rust-lang/cargo/pull/13492/)
 
-<a id="1.78.0-Misc"></a>
-
-Misc
-----
-
-- [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests](https://github.com/rust-lang/rust/pull/114651/)
-
 <a id="1.78.0-Compatibility-Notes"></a>
 
 Compatibility Notes
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index 062447ea03f..d188750bfe1 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -209,6 +209,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
         }
     }
 
+    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+        C: HasDataLayout,
+    {
+        match self.backend_repr {
+            BackendRepr::Vector { .. } => self.size == expected_size,
+            BackendRepr::Memory { .. } => {
+                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
+                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        }
+    }
+
     pub fn is_adt<C>(self) -> bool
     where
         Ty: TyAbiInterface<'a, C>,
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 44bb44cb728..61f2f91635d 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -23,7 +23,7 @@ use crate::ast::*;
 use crate::ptr::P;
 use crate::token::{self, Token};
 use crate::tokenstream::*;
-use crate::visit::{AssocCtxt, BoundKind};
+use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
 
 pub trait ExpectOne<A: Array> {
     fn expect_one(self, err: &'static str) -> A::Item;
@@ -37,7 +37,16 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
 }
 
 pub trait WalkItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor);
+    type Ctxt;
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        ctxt: Self::Ctxt,
+        visitor: &mut impl MutVisitor,
+    );
 }
 
 pub trait MutVisitor: Sized {
@@ -95,8 +104,16 @@ pub trait MutVisitor: Sized {
         walk_use_tree(self, use_tree);
     }
 
+    fn visit_foreign_item(&mut self, ni: &mut P<ForeignItem>) {
+        walk_item(self, ni);
+    }
+
     fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
-        walk_flat_map_item(self, ni)
+        walk_flat_map_foreign_item(self, ni)
+    }
+
+    fn visit_item(&mut self, i: &mut P<Item>) {
+        walk_item(self, i);
     }
 
     fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
@@ -107,16 +124,24 @@ pub trait MutVisitor: Sized {
         walk_fn_header(self, header);
     }
 
+    fn visit_field_def(&mut self, fd: &mut FieldDef) {
+        walk_field_def(self, fd);
+    }
+
     fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
         walk_flat_map_field_def(self, fd)
     }
 
+    fn visit_assoc_item(&mut self, i: &mut P<AssocItem>, ctxt: AssocCtxt) {
+        walk_assoc_item(self, i, ctxt)
+    }
+
     fn flat_map_assoc_item(
         &mut self,
         i: P<AssocItem>,
-        _ctxt: AssocCtxt,
+        ctxt: AssocCtxt,
     ) -> SmallVec<[P<AssocItem>; 1]> {
-        walk_flat_map_item(self, i)
+        walk_flat_map_assoc_item(self, i, ctxt)
     }
 
     fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
@@ -144,6 +169,10 @@ pub trait MutVisitor: Sized {
         walk_flat_map_stmt(self, s)
     }
 
+    fn visit_arm(&mut self, arm: &mut Arm) {
+        walk_arm(self, arm);
+    }
+
     fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
         walk_flat_map_arm(self, arm)
     }
@@ -190,6 +219,10 @@ pub trait MutVisitor: Sized {
         walk_foreign_mod(self, nm);
     }
 
+    fn visit_variant(&mut self, v: &mut Variant) {
+        walk_variant(self, v);
+    }
+
     fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
         walk_flat_map_variant(self, v)
     }
@@ -242,6 +275,10 @@ pub trait MutVisitor: Sized {
         walk_attribute(self, at);
     }
 
+    fn visit_param(&mut self, param: &mut Param) {
+        walk_param(self, param);
+    }
+
     fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
         walk_flat_map_param(self, param)
     }
@@ -262,6 +299,10 @@ pub trait MutVisitor: Sized {
         walk_variant_data(self, vdata);
     }
 
+    fn visit_generic_param(&mut self, param: &mut GenericParam) {
+        walk_generic_param(self, param)
+    }
+
     fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
         walk_flat_map_generic_param(self, param)
     }
@@ -278,6 +319,10 @@ pub trait MutVisitor: Sized {
         walk_mt(self, mt);
     }
 
+    fn visit_expr_field(&mut self, f: &mut ExprField) {
+        walk_expr_field(self, f);
+    }
+
     fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
         walk_flat_map_expr_field(self, f)
     }
@@ -302,6 +347,10 @@ pub trait MutVisitor: Sized {
         // Do nothing.
     }
 
+    fn visit_pat_field(&mut self, fp: &mut PatField) {
+        walk_pat_field(self, fp)
+    }
+
     fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
         walk_flat_map_pat_field(self, fp)
     }
@@ -321,6 +370,10 @@ pub trait MutVisitor: Sized {
     fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
         walk_capture_by(self, capture_by)
     }
+
+    fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) {
+        walk_fn_ret_ty(self, fn_ret_ty)
+    }
 }
 
 /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
@@ -416,16 +469,20 @@ pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: &
     vis.visit_span(close);
 }
 
-pub fn walk_flat_map_pat_field<T: MutVisitor>(
-    vis: &mut T,
-    mut fp: PatField,
-) -> SmallVec<[PatField; 1]> {
-    let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp;
+pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) {
+    let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_ident(ident);
     vis.visit_pat(pat);
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_pat_field<T: MutVisitor>(
+    vis: &mut T,
+    mut fp: PatField,
+) -> SmallVec<[PatField; 1]> {
+    vis.visit_pat_field(&mut fp);
     smallvec![fp]
 }
 
@@ -446,14 +503,18 @@ fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) {
     vis.visit_span(span);
 }
 
-pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
-    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
+pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
+    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     visit_opt(guard, |guard| vis.visit_expr(guard));
     visit_opt(body, |body| vis.visit_expr(body));
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
+    vis.visit_arm(&mut arm);
     smallvec![arm]
 }
 
@@ -530,11 +591,8 @@ fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) {
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
-pub fn walk_flat_map_variant<T: MutVisitor>(
-    visitor: &mut T,
-    mut variant: Variant,
-) -> SmallVec<[Variant; 1]> {
-    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
+pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) {
+    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant;
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
@@ -542,6 +600,13 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
     visitor.visit_variant_data(data);
     visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
     visitor.visit_span(span);
+}
+
+pub fn walk_flat_map_variant<T: MutVisitor>(
+    vis: &mut T,
+    mut variant: Variant,
+) -> SmallVec<[Variant; 1]> {
+    vis.visit_variant(&mut variant);
     smallvec![variant]
 }
 
@@ -600,7 +665,7 @@ fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut An
 fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
     let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
     visit_thin_vec(inputs, |input| vis.visit_ty(input));
-    walk_fn_ret_ty(vis, output);
+    vis.visit_fn_ret_ty(output);
     vis.visit_span(span);
     vis.visit_span(inputs_span);
 }
@@ -672,13 +737,17 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
     vis.visit_span(span);
 }
 
-pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
-    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
+pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) {
+    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     vis.visit_ty(ty);
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
+    vis.visit_param(&mut param);
     smallvec![param]
 }
 
@@ -880,7 +949,7 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
 
 fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
     match kind {
-        FnKind::Fn(FnSig { header, decl, span }, generics, body) => {
+        FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
             // Identifier and visibility are visited as a part of the item.
             vis.visit_fn_header(header);
             vis.visit_generics(generics);
@@ -890,8 +959,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
             }
             vis.visit_span(span);
         }
-        FnKind::Closure(binder, decl, body) => {
+        FnKind::Closure(binder, coroutine_kind, decl, body) => {
             vis.visit_closure_binder(binder);
+            coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
             vis.visit_fn_decl(decl);
             vis.visit_expr(body);
         }
@@ -901,7 +971,7 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
 fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
     let FnDecl { inputs, output } = decl.deref_mut();
     inputs.flat_map_in_place(|param| vis.flat_map_param(param));
-    walk_fn_ret_ty(vis, output);
+    vis.visit_fn_ret_ty(output);
 }
 
 fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
@@ -936,11 +1006,8 @@ fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCaptu
     }
 }
 
-pub fn walk_flat_map_generic_param<T: MutVisitor>(
-    vis: &mut T,
-    mut param: GenericParam,
-) -> SmallVec<[GenericParam; 1]> {
-    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
+pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) {
+    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_ident(ident);
@@ -958,6 +1025,13 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
     if let Some(colon_span) = colon_span {
         vis.visit_span(colon_span);
     }
+}
+
+pub fn walk_flat_map_generic_param<T: MutVisitor>(
+    vis: &mut T,
+    mut param: GenericParam,
+) -> SmallVec<[GenericParam; 1]> {
+    vis.visit_generic_param(&mut param);
     smallvec![param]
 }
 
@@ -1040,30 +1114,38 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
     vis.visit_span(span);
 }
 
-pub fn walk_flat_map_field_def<T: MutVisitor>(
-    visitor: &mut T,
-    mut fd: FieldDef,
-) -> SmallVec<[FieldDef; 1]> {
-    let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd;
+pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
+    let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = fd;
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visit_opt(ident, |ident| visitor.visit_ident(ident));
     visitor.visit_ty(ty);
     visitor.visit_span(span);
-    smallvec![fd]
 }
 
-pub fn walk_flat_map_expr_field<T: MutVisitor>(
+pub fn walk_flat_map_field_def<T: MutVisitor>(
     vis: &mut T,
-    mut f: ExprField,
-) -> SmallVec<[ExprField; 1]> {
-    let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f;
+    mut fd: FieldDef,
+) -> SmallVec<[FieldDef; 1]> {
+    vis.visit_field_def(&mut fd);
+    smallvec![fd]
+}
+
+pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) {
+    let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_ident(ident);
     vis.visit_expr(expr);
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_expr_field<T: MutVisitor>(
+    vis: &mut T,
+    mut f: ExprField,
+) -> SmallVec<[ExprField; 1]> {
+    vis.visit_expr_field(&mut f);
     smallvec![f]
 }
 
@@ -1079,17 +1161,29 @@ pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
     vis.visit_span(span);
 }
 
-pub fn walk_item_kind(
-    kind: &mut impl WalkItemKind,
+pub fn walk_item_kind<K: WalkItemKind>(
+    kind: &mut K,
     span: Span,
     id: NodeId,
+    ident: &mut Ident,
+    visibility: &mut Visibility,
+    ctxt: K::Ctxt,
     vis: &mut impl MutVisitor,
 ) {
-    kind.walk(span, id, vis)
+    kind.walk(span, id, ident, visibility, ctxt, vis)
 }
 
 impl WalkItemKind for ItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) {
+    type Ctxt = ();
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        _ctxt: Self::Ctxt,
+        vis: &mut impl MutVisitor,
+    ) {
         match self {
             ItemKind::ExternCrate(_orig_name) => {}
             ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
@@ -1102,7 +1196,11 @@ impl WalkItemKind for ItemKind {
             }
             ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
                 visit_defaultness(vis, defaultness);
-                vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
+                vis.visit_fn(
+                    FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
+                    span,
+                    id,
+                );
             }
             ItemKind::Mod(safety, mod_kind) => {
                 visit_safety(vis, safety);
@@ -1201,14 +1299,27 @@ impl WalkItemKind for ItemKind {
 }
 
 impl WalkItemKind for AssocItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
+    type Ctxt = AssocCtxt;
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        ctxt: Self::Ctxt,
+        visitor: &mut impl MutVisitor,
+    ) {
         match self {
             AssocItemKind::Const(item) => {
                 visit_const_item(item, visitor);
             }
             AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
                 visit_defaultness(visitor, defaultness);
-                visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
+                visitor.visit_fn(
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
+                    span,
+                    id,
+                );
             }
             AssocItemKind::Type(box TyAlias {
                 defaultness,
@@ -1288,24 +1399,62 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
     vis.visit_span(inject_use_span);
 }
 
-/// Mutates one item, returning the item again.
-pub fn walk_flat_map_item<K: WalkItemKind>(
+pub fn walk_item(visitor: &mut impl MutVisitor, item: &mut P<Item<impl WalkItemKind<Ctxt = ()>>>) {
+    walk_item_ctxt(visitor, item, ())
+}
+
+pub fn walk_assoc_item(visitor: &mut impl MutVisitor, item: &mut P<AssocItem>, ctxt: AssocCtxt) {
+    walk_item_ctxt(visitor, item, ctxt)
+}
+
+fn walk_item_ctxt<K: WalkItemKind>(
     visitor: &mut impl MutVisitor,
-    mut item: P<Item<K>>,
-) -> SmallVec<[P<Item<K>>; 1]> {
+    item: &mut P<Item<K>>,
+    ctxt: K::Ctxt,
+) {
     let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visitor.visit_ident(ident);
-    kind.walk(*span, *id, visitor);
+    kind.walk(*span, *id, ident, vis, ctxt, visitor);
     visit_lazy_tts(visitor, tokens);
     visitor.visit_span(span);
+}
+
+pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> {
+    vis.visit_item(&mut item);
+    smallvec![item]
+}
+
+pub fn walk_flat_map_foreign_item(
+    vis: &mut impl MutVisitor,
+    mut item: P<ForeignItem>,
+) -> SmallVec<[P<ForeignItem>; 1]> {
+    vis.visit_foreign_item(&mut item);
+    smallvec![item]
+}
+
+pub fn walk_flat_map_assoc_item(
+    vis: &mut impl MutVisitor,
+    mut item: P<AssocItem>,
+    ctxt: AssocCtxt,
+) -> SmallVec<[P<AssocItem>; 1]> {
+    vis.visit_assoc_item(&mut item, ctxt);
     smallvec![item]
 }
 
 impl WalkItemKind for ForeignItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
+    type Ctxt = ();
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        _ctxt: Self::Ctxt,
+        visitor: &mut impl MutVisitor,
+    ) {
         match self {
             ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
                 visitor.visit_ty(ty);
@@ -1313,7 +1462,11 @@ impl WalkItemKind for ForeignItemKind {
             }
             ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
                 visit_defaultness(visitor, defaultness);
-                visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
+                visitor.visit_fn(
+                    FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
+                    span,
+                    id,
+                );
             }
             ForeignItemKind::TyAlias(box TyAlias {
                 defaultness,
@@ -1522,9 +1675,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
             fn_arg_span,
         }) => {
             visit_constness(vis, constness);
-            coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
             vis.visit_capture_by(capture_clause);
-            vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id);
+            vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
             vis.visit_span(fn_decl_span);
             vis.visit_span(fn_arg_span);
         }
@@ -1785,8 +1937,20 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
 #[derive(Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>),
+    Fn(
+        FnCtxt,
+        &'a mut Ident,
+        &'a mut FnSig,
+        &'a mut Visibility,
+        &'a mut Generics,
+        &'a mut Option<P<Block>>,
+    ),
 
     /// E.g., `|x, y| body`.
-    Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>),
+    Closure(
+        &'a mut ClosureBinder,
+        &'a mut Option<CoroutineKind>,
+        &'a mut P<FnDecl>,
+        &'a mut P<Expr>,
+    ),
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 2f8115441de..0302c9fa7f8 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -66,7 +66,7 @@ impl BoundKind {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
+    Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
 
     /// E.g., `|x, y| body`.
     Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
@@ -112,11 +112,15 @@ pub enum LifetimeCtxt {
     GenericArg,
 }
 
-pub trait WalkItemKind: Sized {
+pub trait WalkItemKind {
+    type Ctxt;
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        visibility: &'a Visibility,
+        ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result;
 }
@@ -200,8 +204,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
         walk_param_bound(self, bounds)
     }
-    fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
-        walk_precise_capturing_arg(self, arg);
+    fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result {
+        walk_precise_capturing_arg(self, arg)
     }
     fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
         walk_poly_trait_ref(self, t)
@@ -268,8 +272,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result {
         walk_fn_ret_ty(self, ret_ty)
     }
-    fn visit_fn_header(&mut self, _header: &'ast FnHeader) -> Self::Result {
-        Self::Result::output()
+    fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result {
+        walk_fn_header(self, header)
     }
     fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result {
         walk_expr_field(self, f)
@@ -292,6 +296,15 @@ pub trait Visitor<'ast>: Sized {
     fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result {
         Self::Result::output()
     }
+    fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result {
+        Self::Result::output()
+    }
+    fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result {
+        walk_fn_decl(self, fn_decl)
+    }
+    fn visit_qself(&mut self, qs: &'ast Option<P<QSelf>>) -> Self::Result {
+        walk_qself(self, qs)
+    }
 }
 
 pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
@@ -337,16 +350,19 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR
 }
 
 impl WalkItemKind for ItemKind {
+    type Ctxt = ();
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        _ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        vis: &'a Visibility,
+        _ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result {
-        let Item { id, span, vis, ident, .. } = item;
         match self {
             ItemKind::ExternCrate(_rename) => {}
-            ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)),
+            ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)),
             ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
@@ -357,8 +373,8 @@ impl WalkItemKind for ItemKind {
                 visit_opt!(visitor, visit_expr, expr);
             }
             ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref());
-                try_visit!(visitor.visit_fn(kind, *span, *id));
+                let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
+                try_visit!(visitor.visit_fn(kind, span, id));
             }
             ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
                 ModKind::Loaded(items, _inline, _inner_span) => {
@@ -415,7 +431,7 @@ impl WalkItemKind for ItemKind {
                 walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
             }
             ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
-            ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)),
+            ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)),
             ItemKind::Delegation(box Delegation {
                 id,
                 qself,
@@ -424,14 +440,14 @@ impl WalkItemKind for ItemKind {
                 body,
                 from_glob: _,
             }) => {
-                try_visit!(walk_qself(visitor, qself));
+                try_visit!(visitor.visit_qself(qself));
                 try_visit!(visitor.visit_path(path, *id));
                 visit_opt!(visitor, visit_ident, rename);
                 visit_opt!(visitor, visit_block, body);
             }
             ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
-                try_visit!(walk_qself(visitor, qself));
-                try_visit!(visitor.visit_path(prefix, *id));
+                try_visit!(visitor.visit_qself(qself));
+                try_visit!(visitor.visit_path(prefix, id));
                 if let Some(suffixes) = suffixes {
                     for (ident, rename) in suffixes {
                         visitor.visit_ident(ident);
@@ -447,13 +463,6 @@ impl WalkItemKind for ItemKind {
     }
 }
 
-pub fn walk_item<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    item: &'a Item<impl WalkItemKind>,
-) -> V::Result {
-    walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/)
-}
-
 pub fn walk_enum_def<'a, V: Visitor<'a>>(
     visitor: &mut V,
     EnumDef { variants }: &'a EnumDef,
@@ -508,10 +517,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
             let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } =
                 &**function_declaration;
             walk_list!(visitor, visit_generic_param, generic_params);
-            try_visit!(walk_fn_decl(visitor, decl));
+            try_visit!(visitor.visit_fn_decl(decl));
         }
         TyKind::Path(maybe_qself, path) => {
-            try_visit!(walk_qself(visitor, maybe_qself));
+            try_visit!(visitor.visit_qself(maybe_qself));
             try_visit!(visitor.visit_path(path, *id));
         }
         TyKind::Pat(ty, pat) => {
@@ -642,16 +651,16 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
     let Pat { id, kind, span: _, tokens: _ } = pattern;
     match kind {
         PatKind::TupleStruct(opt_qself, path, elems) => {
-            try_visit!(walk_qself(visitor, opt_qself));
+            try_visit!(visitor.visit_qself(opt_qself));
             try_visit!(visitor.visit_path(path, *id));
             walk_list!(visitor, visit_pat, elems);
         }
         PatKind::Path(opt_qself, path) => {
-            try_visit!(walk_qself(visitor, opt_qself));
+            try_visit!(visitor.visit_qself(opt_qself));
             try_visit!(visitor.visit_path(path, *id))
         }
         PatKind::Struct(opt_qself, path, fields, _rest) => {
-            try_visit!(walk_qself(visitor, opt_qself));
+            try_visit!(visitor.visit_qself(opt_qself));
             try_visit!(visitor.visit_path(path, *id));
             walk_list!(visitor, visit_pat_field, fields);
         }
@@ -681,20 +690,23 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
 }
 
 impl WalkItemKind for ForeignItemKind {
+    type Ctxt = ();
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        _ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        vis: &'a Visibility,
+        _ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result {
-        let &Item { id, span, ident, ref vis, .. } = item;
         match self {
             ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
             ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
+                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             ForeignItemKind::TyAlias(box TyAlias {
@@ -730,14 +742,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
 pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
     visitor: &mut V,
     arg: &'a PreciseCapturingArg,
-) {
+) -> V::Result {
     match arg {
-        PreciseCapturingArg::Lifetime(lt) => {
-            visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg);
-        }
-        PreciseCapturingArg::Arg(path, id) => {
-            visitor.visit_path(path, *id);
-        }
+        PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg),
+        PreciseCapturingArg::Arg(path, id) => visitor.visit_path(path, *id),
     }
 }
 
@@ -817,6 +825,12 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy)
     V::Result::output()
 }
 
+pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result {
+    let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header;
+    visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
+    V::Result::output()
+}
+
 pub fn walk_fn_decl<'a, V: Visitor<'a>>(
     visitor: &mut V,
     FnDecl { inputs, output }: &'a FnDecl,
@@ -831,12 +845,13 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
             // Identifier and visibility are visited as a part of the item.
             try_visit!(visitor.visit_fn_header(header));
             try_visit!(visitor.visit_generics(generics));
-            try_visit!(walk_fn_decl(visitor, decl));
+            try_visit!(visitor.visit_fn_decl(decl));
             visit_opt!(visitor, visit_block, body);
         }
-        FnKind::Closure(binder, _coroutine_kind, decl, body) => {
+        FnKind::Closure(binder, coroutine_kind, decl, body) => {
             try_visit!(visitor.visit_closure_binder(binder));
-            try_visit!(walk_fn_decl(visitor, decl));
+            visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
+            try_visit!(visitor.visit_fn_decl(decl));
             try_visit!(visitor.visit_expr(body));
         }
     }
@@ -844,13 +859,16 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
 }
 
 impl WalkItemKind for AssocItemKind {
+    type Ctxt = AssocCtxt;
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        vis: &'a Visibility,
+        ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result {
-        let &Item { id, span, ident, ref vis, .. } = item;
         match self {
             AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
                 try_visit!(visitor.visit_generics(generics));
@@ -858,8 +876,7 @@ impl WalkItemKind for AssocItemKind {
                 visit_opt!(visitor, visit_expr, expr);
             }
             AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind =
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
+                let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             AssocItemKind::Type(box TyAlias {
@@ -884,13 +901,13 @@ impl WalkItemKind for AssocItemKind {
                 body,
                 from_glob: _,
             }) => {
-                try_visit!(walk_qself(visitor, qself));
+                try_visit!(visitor.visit_qself(qself));
                 try_visit!(visitor.visit_path(path, *id));
                 visit_opt!(visitor, visit_ident, rename);
                 visit_opt!(visitor, visit_block, body);
             }
             AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
-                try_visit!(walk_qself(visitor, qself));
+                try_visit!(visitor.visit_qself(qself));
                 try_visit!(visitor.visit_path(prefix, id));
                 if let Some(suffixes) = suffixes {
                     for (ident, rename) in suffixes {
@@ -907,16 +924,31 @@ impl WalkItemKind for AssocItemKind {
     }
 }
 
+pub fn walk_item<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
+) -> V::Result {
+    walk_item_ctxt(visitor, item, ())
+}
+
 pub fn walk_assoc_item<'a, V: Visitor<'a>>(
     visitor: &mut V,
-    item: &'a Item<impl WalkItemKind>,
+    item: &'a AssocItem,
     ctxt: AssocCtxt,
 ) -> V::Result {
-    let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
+    walk_item_ctxt(visitor, item, ctxt)
+}
+
+fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>(
+    visitor: &mut V,
+    item: &'a Item<K>,
+    ctxt: K::Ctxt,
+) -> V::Result {
+    let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item;
     walk_list!(visitor, visit_attribute, attrs);
     try_visit!(visitor.visit_vis(vis));
     try_visit!(visitor.visit_ident(ident));
-    try_visit!(kind.walk(item, ctxt, visitor));
+    try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor));
     V::Result::output()
 }
 
@@ -1005,7 +1037,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(
     visitor: &mut V,
     InlineAsmSym { id, qself, path }: &'a InlineAsmSym,
 ) -> V::Result {
-    try_visit!(walk_qself(visitor, qself));
+    try_visit!(visitor.visit_qself(qself));
     visitor.visit_path(path, *id)
 }
 
@@ -1037,7 +1069,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
         }
         ExprKind::Struct(se) => {
             let StructExpr { qself, path, fields, rest } = &**se;
-            try_visit!(walk_qself(visitor, qself));
+            try_visit!(visitor.visit_qself(qself));
             try_visit!(visitor.visit_path(path, *id));
             walk_list!(visitor, visit_expr_field, fields);
             match rest {
@@ -1146,7 +1178,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
         }
         ExprKind::Underscore => {}
         ExprKind::Path(maybe_qself, path) => {
-            try_visit!(walk_qself(visitor, maybe_qself));
+            try_visit!(visitor.visit_qself(maybe_qself));
             try_visit!(visitor.visit_path(path, *id));
         }
         ExprKind::Break(opt_label, opt_expr) => {
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index c47c12b4fd1..8cc4521e0a7 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -9,6 +9,7 @@ doctest = false
 [dependencies]
 # tidy-alphabetical-start
 rustc_ast = { path = "../rustc_ast" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index a5ee6713be8..f704320c71d 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -103,6 +103,12 @@ ast_lowering_invalid_asm_template_modifier_reg_class =
 ast_lowering_invalid_asm_template_modifier_sym =
     asm template modifiers are not allowed for `sym` arguments
 
+ast_lowering_invalid_legacy_const_generic_arg =
+    invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+
+ast_lowering_invalid_legacy_const_generic_arg_suggestion =
+    try using a const generic argument instead
+
 ast_lowering_invalid_register =
     invalid register `{$reg}`: {$error}
 
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 6b39c2d3955..e6a3f939f2d 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -451,3 +451,26 @@ pub(crate) struct YieldInClosure {
     #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
     pub suggestion: Option<Span>,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
+pub(crate) struct InvalidLegacyConstGenericArg {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub suggestion: UseConstGenericArg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    ast_lowering_invalid_legacy_const_generic_arg_suggestion,
+    applicability = "maybe-incorrect"
+)]
+pub(crate) struct UseConstGenericArg {
+    #[suggestion_part(code = "::<{const_args}>")]
+    pub end_of_fn: Span,
+    pub const_args: String,
+    pub other_args: String,
+    #[suggestion_part(code = "{other_args}")]
+    pub call_args: Span,
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index b7cf2d252dc..3af29838b72 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,18 +1,22 @@
 use std::assert_matches::assert_matches;
+use std::ops::ControlFlow;
 
 use rustc_ast::ptr::P as AstP;
 use rustc_ast::*;
+use rustc_ast_pretty::pprust::expr_to_string;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::HirId;
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::span_bug;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{Spanned, respan};
 use rustc_span::symbol::{Ident, Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, DesugaringKind, Span};
 use thin_vec::{ThinVec, thin_vec};
+use visit::{Visitor, walk_expr};
 
 use super::errors::{
     AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
@@ -23,9 +27,32 @@ use super::errors::{
 use super::{
     GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
 };
-use crate::errors::YieldInClosure;
+use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
 use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated};
 
+struct WillCreateDefIdsVisitor {}
+
+impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
+    type Result = ControlFlow<Span>;
+
+    fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
+        ControlFlow::Break(c.value.span)
+    }
+
+    fn visit_item(&mut self, item: &'v Item) -> Self::Result {
+        ControlFlow::Break(item.span)
+    }
+
+    fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
+        match ex.kind {
+            ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => {
+                ControlFlow::Break(ex.span)
+            }
+            _ => walk_expr(self, ex),
+        }
+    }
+}
+
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
         self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
@@ -396,10 +423,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
             unreachable!();
         };
 
+        let mut error = None;
+        let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| {
+            // Avoid emitting the error multiple times.
+            if error.is_none() {
+                let mut const_args = vec![];
+                let mut other_args = vec![];
+                for (idx, arg) in args.iter().enumerate() {
+                    if legacy_args_idx.contains(&idx) {
+                        const_args.push(format!("{{ {} }}", expr_to_string(arg)));
+                    } else {
+                        other_args.push(expr_to_string(arg));
+                    }
+                }
+                let suggestion = UseConstGenericArg {
+                    end_of_fn: f.span.shrink_to_hi(),
+                    const_args: const_args.join(", "),
+                    other_args: other_args.join(", "),
+                    call_args: args[0].span.to(args.last().unwrap().span),
+                };
+                error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion }));
+            }
+            error.unwrap()
+        };
+
         // Split the arguments into const generics and normal arguments
         let mut real_args = vec![];
         let mut generic_args = ThinVec::new();
-        for (idx, arg) in args.into_iter().enumerate() {
+        for (idx, arg) in args.iter().cloned().enumerate() {
             if legacy_args_idx.contains(&idx) {
                 let parent_def_id = self.current_def_id_parent;
                 let node_id = self.next_node_id();
@@ -410,7 +461,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
                 }
 
-                let anon_const = AnonConst { id: node_id, value: arg };
+                let mut visitor = WillCreateDefIdsVisitor {};
+                let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
+                    AstP(Expr {
+                        id: self.next_node_id(),
+                        kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
+                        span: f.span,
+                        attrs: [].into(),
+                        tokens: None,
+                    })
+                } else {
+                    arg
+                };
+
+                let anon_const = AnonConst { id: node_id, value: const_value };
                 generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
             } else {
                 real_args.push(arg);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 5a0e9e8aec0..0b2969a49ba 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -738,7 +738,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         allow_internal_unstable: Option<Lrc<[Symbol]>>,
     ) -> Span {
         self.tcx.with_stable_hashing_context(|hcx| {
-            span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx)
+            span.mark_with_reason(allow_internal_unstable, reason, span.edition(), hcx)
         })
     }
 
@@ -2052,6 +2052,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
+    /// Used when lowering a type argument that turned out to actually be a const argument.
+    ///
+    /// Only use for that purpose since otherwise it will create a duplicate def.
     #[instrument(level = "debug", skip(self))]
     fn lower_const_path_to_const_arg(
         &mut self,
@@ -2060,51 +2063,58 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         ty_id: NodeId,
         span: Span,
     ) -> &'hir hir::ConstArg<'hir> {
-        let ct_kind = match res {
-            Res::Def(DefKind::ConstParam, _) => {
-                let qpath = self.lower_qpath(
-                    ty_id,
-                    &None,
-                    path,
-                    ParamMode::Optional,
-                    AllowReturnTypeNotation::No,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),
-                    None,
-                );
-                hir::ConstArgKind::Path(qpath)
-            }
-            _ => {
-                // Construct an AnonConst where the expr is the "ty"'s path.
+        let tcx = self.tcx;
 
-                let parent_def_id = self.current_def_id_parent;
-                let node_id = self.next_node_id();
-                let span = self.lower_span(span);
-
-                // Add a definition for the in-band const def.
-                let def_id =
-                    self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
-                let hir_id = self.lower_node_id(node_id);
+        // FIXME(min_generic_const_args): we only allow one-segment const paths for now
+        let ct_kind = if path.is_potential_trivial_const_arg()
+            && (tcx.features().min_generic_const_args()
+                || matches!(res, Res::Def(DefKind::ConstParam, _)))
+        {
+            let qpath = self.lower_qpath(
+                ty_id,
+                &None,
+                path,
+                ParamMode::Optional,
+                AllowReturnTypeNotation::No,
+                // FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
+                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                None,
+            );
+            hir::ConstArgKind::Path(qpath)
+        } else {
+            // Construct an AnonConst where the expr is the "ty"'s path.
+
+            let parent_def_id = self.current_def_id_parent;
+            let node_id = self.next_node_id();
+            let span = self.lower_span(span);
+
+            // Add a definition for the in-band const def.
+            // We're lowering a const argument that was originally thought to be a type argument,
+            // so the def collector didn't create the def ahead of time. That's why we have to do
+            // it here.
+            let def_id =
+                self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
+            let hir_id = self.lower_node_id(node_id);
+
+            let path_expr = Expr {
+                id: ty_id,
+                kind: ExprKind::Path(None, path.clone()),
+                span,
+                attrs: AttrVec::new(),
+                tokens: None,
+            };
 
-                let path_expr = Expr {
-                    id: ty_id,
-                    kind: ExprKind::Path(None, path.clone()),
+            let ct = self.with_new_scopes(span, |this| {
+                self.arena.alloc(hir::AnonConst {
+                    def_id,
+                    hir_id,
+                    body: this.with_def_id_parent(def_id, |this| {
+                        this.lower_const_body(path_expr.span, Some(&path_expr))
+                    }),
                     span,
-                    attrs: AttrVec::new(),
-                    tokens: None,
-                };
-
-                let ct = self.with_new_scopes(span, |this| {
-                    self.arena.alloc(hir::AnonConst {
-                        def_id,
-                        hir_id,
-                        body: this.with_def_id_parent(def_id, |this| {
-                            this.lower_const_body(path_expr.span, Some(&path_expr))
-                        }),
-                        span,
-                    })
-                });
-                hir::ConstArgKind::Anon(ct)
-            }
+                })
+            });
+            hir::ConstArgKind::Anon(ct)
         };
 
         self.arena.alloc(hir::ConstArg {
@@ -2122,6 +2132,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     #[instrument(level = "debug", skip(self))]
     fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
+        let tcx = self.tcx;
         // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
         // currently have to be wrapped in curly brackets, so it's necessary to special-case.
         let expr = if let ExprKind::Block(block, _) = &anon.value.kind
@@ -2135,18 +2146,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
         let maybe_res =
             self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
-        debug!("res={:?}", maybe_res);
-        // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
-        if let Some(res) = maybe_res
-            && let Res::Def(DefKind::ConstParam, _) = res
-            && let ExprKind::Path(qself, path) = &expr.kind
+        // FIXME(min_generic_const_args): we only allow one-segment const paths for now
+        if let ExprKind::Path(None, path) = &expr.kind
+            && path.is_potential_trivial_const_arg()
+            && (tcx.features().min_generic_const_args()
+                || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
         {
             let qpath = self.lower_qpath(
                 expr.id,
-                qself,
+                &None,
                 path,
                 ParamMode::Optional,
                 AllowReturnTypeNotation::No,
+                // FIXME(min_generic_const_args): update for `fn foo() -> Bar<FOO<impl Trait>>` support
                 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                 None,
             );
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index dee48586f34..07a6f4e5ee7 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -946,8 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
                 self.visit_vis(&item.vis);
                 self.visit_ident(&item.ident);
-                let kind =
-                    FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
+                let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
                 self.visit_fn(kind, item.span, item.id);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
@@ -1476,14 +1475,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(&item.ident);
-                let kind = FnKind::Fn(
-                    FnCtxt::Assoc(ctxt),
-                    item.ident,
-                    sig,
-                    &item.vis,
-                    generics,
-                    body.as_deref(),
-                );
+                let kind =
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
                 walk_list!(self, visit_attribute, &item.attrs);
                 self.visit_fn(kind, item.span, item.id);
             }
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 88c6bde3106..86752da79ae 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -18,7 +18,6 @@
 pub mod ast_validation;
 mod errors;
 pub mod feature_gate;
-pub mod node_count;
 pub mod show_span;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
deleted file mode 100644
index 9e7204df8ad..00000000000
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ /dev/null
@@ -1,129 +0,0 @@
-// Simply gives a rough count of the number of nodes in an AST.
-
-use rustc_ast::visit::*;
-use rustc_ast::*;
-use rustc_span::Span;
-use rustc_span::symbol::Ident;
-
-pub struct NodeCounter {
-    pub count: usize,
-}
-
-impl NodeCounter {
-    pub fn new() -> NodeCounter {
-        NodeCounter { count: 0 }
-    }
-}
-
-impl<'ast> Visitor<'ast> for NodeCounter {
-    fn visit_ident(&mut self, _ident: &Ident) {
-        self.count += 1;
-    }
-    fn visit_foreign_item(&mut self, i: &ForeignItem) {
-        self.count += 1;
-        walk_item(self, i)
-    }
-    fn visit_item(&mut self, i: &Item) {
-        self.count += 1;
-        walk_item(self, i)
-    }
-    fn visit_local(&mut self, l: &Local) {
-        self.count += 1;
-        walk_local(self, l)
-    }
-    fn visit_block(&mut self, b: &Block) {
-        self.count += 1;
-        walk_block(self, b)
-    }
-    fn visit_stmt(&mut self, s: &Stmt) {
-        self.count += 1;
-        walk_stmt(self, s)
-    }
-    fn visit_arm(&mut self, a: &Arm) {
-        self.count += 1;
-        walk_arm(self, a)
-    }
-    fn visit_pat(&mut self, p: &Pat) {
-        self.count += 1;
-        walk_pat(self, p)
-    }
-    fn visit_expr(&mut self, ex: &Expr) {
-        self.count += 1;
-        walk_expr(self, ex)
-    }
-    fn visit_ty(&mut self, t: &Ty) {
-        self.count += 1;
-        walk_ty(self, t)
-    }
-    fn visit_generic_param(&mut self, param: &GenericParam) {
-        self.count += 1;
-        walk_generic_param(self, param)
-    }
-    fn visit_generics(&mut self, g: &Generics) {
-        self.count += 1;
-        walk_generics(self, g)
-    }
-    fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: Span, _: NodeId) {
-        self.count += 1;
-        walk_fn(self, fk)
-    }
-    fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) {
-        self.count += 1;
-        walk_assoc_item(self, ti, ctxt);
-    }
-    fn visit_trait_ref(&mut self, t: &TraitRef) {
-        self.count += 1;
-        walk_trait_ref(self, t)
-    }
-    fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) {
-        self.count += 1;
-        walk_param_bound(self, bounds)
-    }
-    fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) {
-        self.count += 1;
-        walk_poly_trait_ref(self, t)
-    }
-    fn visit_variant_data(&mut self, s: &VariantData) {
-        self.count += 1;
-        walk_struct_def(self, s)
-    }
-    fn visit_field_def(&mut self, s: &FieldDef) {
-        self.count += 1;
-        walk_field_def(self, s)
-    }
-    fn visit_enum_def(&mut self, enum_definition: &EnumDef) {
-        self.count += 1;
-        walk_enum_def(self, enum_definition)
-    }
-    fn visit_variant(&mut self, v: &Variant) {
-        self.count += 1;
-        walk_variant(self, v)
-    }
-    fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) {
-        self.count += 1;
-        walk_lifetime(self, lifetime)
-    }
-    fn visit_mac_call(&mut self, mac: &MacCall) {
-        self.count += 1;
-        walk_mac(self, mac)
-    }
-    fn visit_path(&mut self, path: &Path, _id: NodeId) {
-        self.count += 1;
-        walk_path(self, path)
-    }
-    fn visit_use_tree(&mut self, use_tree: &UseTree, id: NodeId, _nested: bool) {
-        self.count += 1;
-        walk_use_tree(self, use_tree, id)
-    }
-    fn visit_generic_args(&mut self, generic_args: &GenericArgs) {
-        self.count += 1;
-        walk_generic_args(self, generic_args)
-    }
-    fn visit_assoc_item_constraint(&mut self, constraint: &AssocItemConstraint) {
-        self.count += 1;
-        walk_assoc_item_constraint(self, constraint)
-    }
-    fn visit_attribute(&mut self, _attr: &Attribute) {
-        self.count += 1;
-    }
-}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index d832decc170..452038bc328 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,93 +1,171 @@
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges};
+use rustc_middle::mir::{
+    self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
+};
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
-use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
+use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
 use tracing::debug;
 
 use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
 
-/// The results of the dataflow analyses used by the borrow checker.
-pub(crate) struct BorrowckResults<'a, 'tcx> {
-    pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>,
-    pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
-    pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>,
-}
-
-/// The transient state of the dataflow analyses used by the borrow checker.
-#[derive(Debug)]
-pub(crate) struct BorrowckDomain<'a, 'tcx> {
-    pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
-    pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
-    pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
+// This analysis is different to most others. Its results aren't computed with
+// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
+// computed individually with `iterate_to_fixpoint`.
+pub(crate) struct Borrowck<'a, 'tcx> {
+    pub(crate) borrows: Borrows<'a, 'tcx>,
+    pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>,
+    pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>,
 }
 
-impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
-    type Direction = Forward;
+impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
     type Domain = BorrowckDomain<'a, 'tcx>;
 
+    const NAME: &'static str = "borrowck";
+
     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
         BorrowckDomain {
-            borrows: self.borrows.analysis.bottom_value(body),
-            uninits: self.uninits.analysis.bottom_value(body),
-            ever_inits: self.ever_inits.analysis.bottom_value(body),
+            borrows: self.borrows.bottom_value(body),
+            uninits: self.uninits.bottom_value(body),
+            ever_inits: self.ever_inits.bottom_value(body),
         }
     }
 
-    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
-        state.borrows.clone_from(self.borrows.entry_set_for_block(block));
-        state.uninits.clone_from(self.uninits.entry_set_for_block(block));
-        state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
+    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
     }
 
-    fn reconstruct_before_statement_effect(
+    fn apply_before_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
-        self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
-        self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
+        self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
+        self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
+        self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
     }
 
-    fn reconstruct_statement_effect(
+    fn apply_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
-        self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
-        self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
+        self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
+        self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
+        self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
     }
 
-    fn reconstruct_before_terminator_effect(
+    fn apply_before_terminator_effect(
         &mut self,
         state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
-        self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
-        self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
-        self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
+        self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
+        self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
+        self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
     }
 
-    fn reconstruct_terminator_effect(
+    fn apply_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
-        term: &mir::Terminator<'tcx>,
+        term: &'mir mir::Terminator<'tcx>,
         loc: Location,
+    ) -> TerminatorEdges<'mir, 'tcx> {
+        self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
+        self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
+        self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
+
+        // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
+        // analysis doesn't use.
+        TerminatorEdges::None
+    }
+
+    fn apply_call_return_effect(
+        &mut self,
+        _state: &mut Self::Domain,
+        _block: BasicBlock,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
+    }
+
+    fn apply_switch_int_edge_effects(
+        &mut self,
+        _block: BasicBlock,
+        _discr: &mir::Operand<'tcx>,
+        _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
     ) {
-        self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
-        self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
-        self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
     }
 }
 
+impl JoinSemiLattice for BorrowckDomain<'_, '_> {
+    fn join(&mut self, _other: &Self) -> bool {
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
+    }
+}
+
+impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
+where
+    C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
+{
+    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("borrows: ")?;
+        self.borrows.fmt_with(ctxt, f)?;
+        f.write_str(" uninits: ")?;
+        self.uninits.fmt_with(ctxt, f)?;
+        f.write_str(" ever_inits: ")?;
+        self.ever_inits.fmt_with(ctxt, f)?;
+        Ok(())
+    }
+
+    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self == old {
+            return Ok(());
+        }
+
+        if self.borrows != old.borrows {
+            f.write_str("borrows: ")?;
+            self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        if self.uninits != old.uninits {
+            f.write_str("uninits: ")?;
+            self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        if self.ever_inits != old.ever_inits {
+            f.write_str("ever_inits: ")?;
+            self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        Ok(())
+    }
+}
+
+/// The transient state of the dataflow analyses used by the borrow checker.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct BorrowckDomain<'a, 'tcx> {
+    pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
+    pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
+    pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
+}
+
 rustc_index::newtype_index! {
     #[orderable]
     #[debug_format = "bw{}"]
@@ -563,6 +641,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
             | mir::StatementKind::Coverage(..)
             | mir::StatementKind::Intrinsic(..)
             | mir::StatementKind::ConstEvalCounter
+            | mir::StatementKind::BackwardIncompatibleDropHint { .. }
             | mir::StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 0897d140d60..90d12ea8328 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -60,7 +60,7 @@ impl<'tcx> UniverseInfo<'tcx> {
             UniverseInfo::RelateTys { expected, found } => {
                 let err = mbcx.infcx.err_ctxt().report_mismatched_types(
                     &cause,
-                    mbcx.param_env,
+                    mbcx.infcx.param_env,
                     expected,
                     found,
                     TypeError::RegionsPlaceholderMismatch,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 454fd14ea74..c11103af476 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -27,7 +27,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
-    self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
+    self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
     suggest_constraining_type_params,
 };
 use rustc_middle::util::CallKind;
@@ -266,7 +266,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 }
             }
 
-            if self.param_env.caller_bounds().iter().any(|c| {
+            if self.infcx.param_env.caller_bounds().iter().any(|c| {
                 c.as_trait_clause().is_some_and(|pred| {
                     pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id())
                 })
@@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     ) -> Option<ty::Mutability> {
         let tcx = self.infcx.tcx;
         let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
-        let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates;
+        let clauses = tcx.predicates_of(callee_did);
 
         // First, is there at least one method on one of `param`'s trait bounds?
         // This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
-        if !clauses.iter().any(|clause| {
+        if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
             clause.as_trait_clause().is_some_and(|tc| {
                 tc.self_ty().skip_binder().is_param(param.index)
                     && tc.polarity() == ty::PredicatePolarity::Positive
@@ -682,9 +682,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 // Normalize before comparing to see through type aliases and projections.
                 let old_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, generic_args);
                 let new_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, new_args);
-                if let Ok(old_ty) = tcx.try_normalize_erasing_regions(self.param_env, old_ty)
-                    && let Ok(new_ty) = tcx.try_normalize_erasing_regions(self.param_env, new_ty)
-                {
+                if let Ok(old_ty) = tcx.try_normalize_erasing_regions(
+                    self.infcx.typing_env(self.infcx.param_env),
+                    old_ty,
+                ) && let Ok(new_ty) = tcx.try_normalize_erasing_regions(
+                    self.infcx.typing_env(self.infcx.param_env),
+                    new_ty,
+                ) {
                     old_ty == new_ty
                 } else {
                     false
@@ -700,23 +704,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 return false;
             }
 
-            // Test the callee's predicates, substituting a reference in for the self ty
-            // in bounds on `param`.
-            clauses.iter().all(|&clause| {
-                let clause_for_ref = clause.kind().map_bound(|kind| match kind {
-                    ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
-                        ClauseKind::Trait(c.with_self_ty(tcx, ref_ty))
-                    }
-                    ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => {
-                        ClauseKind::Projection(c.with_self_ty(tcx, ref_ty))
-                    }
-                    _ => kind,
-                });
+            // Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
+            clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
+                // Normalize before testing to see through type aliases and projections.
+                if let Ok(normalized) = tcx.try_normalize_erasing_regions(
+                    self.infcx.typing_env(self.infcx.param_env),
+                    clause,
+                ) {
+                    clause = normalized;
+                }
                 self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
                     tcx,
                     ObligationCause::dummy(),
-                    self.param_env,
-                    ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
+                    self.infcx.param_env,
+                    clause,
                 ))
             })
         }) {
@@ -904,7 +905,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
         debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
 
-        let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty)
+        let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty)
         else {
             return;
         };
@@ -1304,7 +1305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool {
         let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };
         self.infcx
-            .type_implements_trait(clone_trait_def, [ty], self.param_env)
+            .type_implements_trait(clone_trait_def, [ty], self.infcx.param_env)
             .must_apply_modulo_regions()
     }
 
@@ -1437,7 +1438,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);
         let cause = ObligationCause::misc(span, self.mir_def_id());
 
-        ocx.register_bound(cause, self.param_env, ty, def_id);
+        ocx.register_bound(cause, self.infcx.param_env, ty, def_id);
         let errors = ocx.select_all_or_error();
 
         // Only emit suggestion if all required predicates are on generic
@@ -1957,7 +1958,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 && let ty::Ref(_, inner, _) = rcvr_ty.kind()
                 && let inner = inner.peel_refs()
                 && (Holds { ty: inner }).visit_ty(local_ty).is_break()
-                && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
+                && let None =
+                    self.infcx.type_implements_trait_shallow(clone, inner, self.infcx.param_env)
             {
                 err.span_label(
                     span,
@@ -1989,7 +1991,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             let obligation = Obligation::new(
                 self.infcx.tcx,
                 ObligationCause::dummy(),
-                self.param_env,
+                self.infcx.param_env,
                 trait_ref,
             );
             self.infcx.err_ctxt().suggest_derive(
@@ -3398,7 +3400,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
                 && self
                     .infcx
-                    .type_implements_trait(iter_trait, [return_ty], self.param_env)
+                    .type_implements_trait(iter_trait, [return_ty], self.infcx.param_env)
                     .must_apply_modulo_regions()
             {
                 err.span_suggestion_hidden(
@@ -3837,11 +3839,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             if tcx.is_diagnostic_item(sym::deref_method, method_did) {
                 let deref_target =
                     tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
-                        Instance::try_resolve(tcx, self.param_env, deref_target, method_args)
-                            .transpose()
+                        Instance::try_resolve(
+                            tcx,
+                            self.infcx.typing_env(self.infcx.param_env),
+                            deref_target,
+                            method_args,
+                        )
+                        .transpose()
                     });
                 if let Some(Ok(instance)) = deref_target {
-                    let deref_target_ty = instance.ty(tcx, self.param_env);
+                    let deref_target_ty =
+                        instance.ty(tcx, self.infcx.typing_env(self.infcx.param_env));
                     err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
                     err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
                 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 0797bb49bf9..bda96726738 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -864,7 +864,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
             let kind = call_kind(
                 self.infcx.tcx,
-                self.param_env,
+                self.infcx.typing_env(self.infcx.param_env),
                 method_did,
                 method_args,
                 *fn_span,
@@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
                             Some(def_id) => type_known_to_meet_bound_modulo_regions(
                                 self.infcx,
-                                self.param_env,
+                                self.infcx.param_env,
                                 Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
                                 def_id,
                             ),
@@ -1224,7 +1224,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                 BoundRegionConversionTime::FnCall,
                                 tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
                             )
-                            && self.infcx.can_eq(self.param_env, ty, self_ty)
+                            && self.infcx.can_eq(self.infcx.param_env, ty, self_ty)
                         {
                             err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
                                 span: move_span.shrink_to_hi(),
@@ -1258,7 +1258,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                             if let Some(errors) = self.infcx.type_implements_trait_shallow(
                                 clone_trait,
                                 ty,
-                                self.param_env,
+                                self.infcx.param_env,
                             ) && !has_sugg
                             {
                                 let msg = match &errors[..] {
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 15cc9c20ab7..4ba6b2e94ec 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -305,7 +305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false };
         // This is only going to be ambiguous if there are incoherent impls, because otherwise
         // ambiguity should never happen in MIR.
-        self.infcx.type_implements_trait(copy_trait_def, [ty], self.param_env).may_apply()
+        self.infcx.type_implements_trait(copy_trait_def, [ty], self.infcx.param_env).may_apply()
     }
 
     fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index d064bf098e4..c5ebf3c547e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1242,7 +1242,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                             .type_implements_trait_shallow(
                                 clone_trait,
                                 ty.peel_refs(),
-                                self.param_env,
+                                self.infcx.param_env,
                             )
                             .as_deref()
                         {
@@ -1279,7 +1279,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                 let obligation = traits::Obligation::new(
                                     self.infcx.tcx,
                                     traits::ObligationCause::dummy(),
-                                    self.param_env,
+                                    self.infcx.param_env,
                                     trait_ref,
                                 );
                                 self.infcx.err_ctxt().suggest_derive(
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 807b5576976..c38747f6675 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -952,7 +952,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
             if let Ok(Some(instance)) = ty::Instance::try_resolve(
                 tcx,
-                self.param_env,
+                self.infcx.typing_env(self.infcx.param_env),
                 *fn_did,
                 self.infcx.resolve_vars_if_possible(args),
             ) {
@@ -1091,7 +1091,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             peeled_ty = ref_ty;
             count += 1;
         }
-        if !self.infcx.type_is_copy_modulo_regions(self.param_env, peeled_ty) {
+        if !self.infcx.type_is_copy_modulo_regions(self.infcx.param_env, peeled_ty) {
             return;
         }
 
@@ -1160,7 +1160,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let ocx = ObligationCtxt::new(&self.infcx);
         ocx.register_obligations(preds.iter().map(|(pred, span)| {
             trace!(?pred);
-            Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred)
+            Obligation::misc(tcx, span, self.mir_def_id(), self.infcx.param_env, pred)
         }));
 
         if ocx.select_all_or_error().is_empty() && count > 0 {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 657e6e0907c..16a4f699177 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -36,13 +36,13 @@ use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
-use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
     EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
 };
 use rustc_mir_dataflow::move_paths::{
     InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
 };
+use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
 use rustc_session::lint::builtin::UNUSED_MUT;
 use rustc_span::{Span, Symbol};
 use smallvec::SmallVec;
@@ -50,7 +50,7 @@ use tracing::{debug, instrument};
 
 use crate::borrow_set::{BorrowData, BorrowSet};
 use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
-use crate::dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
+use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
 use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
 use crate::location::LocationTable;
 use crate::nll::PoloniusOutput;
@@ -140,7 +140,6 @@ fn do_mir_borrowck<'tcx>(
 ) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
     let def = input_body.source.def_id().expect_local();
     let infcx = BorrowckInferCtxt::new(tcx, def);
-    let param_env = tcx.param_env(def);
 
     let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
     for var_debug_info in &input_body.var_debug_info {
@@ -175,8 +174,7 @@ fn do_mir_borrowck<'tcx>(
     // will have a lifetime tied to the inference context.
     let mut body_owned = input_body.clone();
     let mut promoted = input_promoted.to_owned();
-    let free_regions =
-        nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted);
+    let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
     let body = &body_owned; // no further changes
 
     // FIXME(-Znext-solver): A bit dubious that we're only registering
@@ -192,7 +190,7 @@ fn do_mir_borrowck<'tcx>(
         .iter_enumerated()
         .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
 
-    let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
+    let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
         .iterate_to_fixpoint(tcx, body, Some("borrowck"))
         .into_results_cursor(body);
 
@@ -213,11 +211,9 @@ fn do_mir_borrowck<'tcx>(
         body,
         &promoted,
         &location_table,
-        param_env,
-        &mut flow_inits,
+        flow_inits,
         &move_data,
         &borrow_set,
-        tcx.closure_captures(def),
         consumer_options,
     );
 
@@ -229,27 +225,6 @@ fn do_mir_borrowck<'tcx>(
     // information.
     nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, &opaque_type_values, diags);
 
-    // The various `flow_*` structures can be large. We drop `flow_inits` here
-    // so it doesn't overlap with the others below. This reduces peak memory
-    // usage significantly on some benchmarks.
-    drop(flow_inits);
-
-    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set).iterate_to_fixpoint(
-        tcx,
-        body,
-        Some("borrowck"),
-    );
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
-        tcx,
-        body,
-        Some("borrowck"),
-    );
-    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
-        tcx,
-        body,
-        Some("borrowck"),
-    );
-
     let movable_coroutine =
         // The first argument is the coroutine type passed by value
         if let Some(local) = body.local_decls.raw.get(1)
@@ -268,7 +243,6 @@ fn do_mir_borrowck<'tcx>(
         let promoted_body = &promoted[idx];
         let mut promoted_mbcx = MirBorrowckCtxt {
             infcx: &infcx,
-            param_env,
             body: promoted_body,
             move_data: &move_data,
             location_table: &location_table, // no need to create a real one for the promoted, it is not used
@@ -308,7 +282,6 @@ fn do_mir_borrowck<'tcx>(
 
     let mut mbcx = MirBorrowckCtxt {
         infcx: &infcx,
-        param_env,
         body,
         move_data: &move_data,
         location_table: &location_table,
@@ -334,16 +307,11 @@ fn do_mir_borrowck<'tcx>(
     // Compute and report region errors, if any.
     mbcx.report_region_errors(nll_errors);
 
-    let mut results = BorrowckResults {
-        ever_inits: flow_ever_inits,
-        uninits: flow_uninits,
-        borrows: flow_borrows,
-    };
-
-    rustc_mir_dataflow::visit_results(
+    let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
+    visit_results(
         body,
         traversal::reverse_postorder(body).map(|(bb, _)| bb),
-        &mut results,
+        &mut flow_results,
         &mut mbcx,
     );
 
@@ -426,15 +394,58 @@ fn do_mir_borrowck<'tcx>(
     (result, body_with_facts)
 }
 
+fn get_flow_results<'a, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &'a Body<'tcx>,
+    move_data: &'a MoveData<'tcx>,
+    borrow_set: &'a BorrowSet<'tcx>,
+    regioncx: &RegionInferenceContext<'tcx>,
+) -> Results<'tcx, Borrowck<'a, 'tcx>> {
+    // We compute these three analyses individually, but them combine them into
+    // a single results so that `mbcx` can visit them all together.
+    let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+
+    let analysis = Borrowck {
+        borrows: borrows.analysis,
+        uninits: uninits.analysis,
+        ever_inits: ever_inits.analysis,
+    };
+
+    assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
+    assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
+    let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
+        itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
+            .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
+            .collect();
+
+    Results { analysis, entry_sets }
+}
+
 pub(crate) struct BorrowckInferCtxt<'tcx> {
     pub(crate) infcx: InferCtxt<'tcx>,
     pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
+    pub(crate) param_env: ParamEnv<'tcx>,
 }
 
 impl<'tcx> BorrowckInferCtxt<'tcx> {
     pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
-        BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
+        let param_env = tcx.param_env(def_id);
+        BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
     }
 
     pub(crate) fn next_region_var<F>(
@@ -513,7 +524,6 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
 
 struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
     infcx: &'infcx BorrowckInferCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
     body: &'a Body<'tcx>,
     move_data: &'a MoveData<'tcx>,
 
@@ -588,14 +598,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
 // 2. loans made in overlapping scopes do not conflict
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
-impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
-    for MirBorrowckCtxt<'a, '_, 'tcx>
-{
-    type Domain = BorrowckDomain<'a, 'tcx>;
-
+impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
+        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
         state: &BorrowckDomain<'a, 'tcx>,
         stmt: &'a Statement<'tcx>,
         location: Location,
@@ -646,6 +652,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
             | StatementKind::Coverage(..)
             // These do not actually affect borrowck
             | StatementKind::ConstEvalCounter
+            // This do not affect borrowck
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
@@ -667,7 +675,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
+        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
         state: &BorrowckDomain<'a, 'tcx>,
         term: &'a Terminator<'tcx>,
         loc: Location,
@@ -780,7 +788,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_after_primary_effect(
         &mut self,
-        _results: &mut R,
+        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
         state: &BorrowckDomain<'a, 'tcx>,
         term: &'a Terminator<'tcx>,
         loc: Location,
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index f76603d5679..be02e2f48df 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -30,7 +30,7 @@ use crate::diagnostics::RegionErrors;
 use crate::facts::{AllFacts, AllFactsExt, RustcFacts};
 use crate::location::LocationTable;
 use crate::region_infer::RegionInferenceContext;
-use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults};
+use crate::type_check::{self, MirTypeckResults};
 use crate::universal_regions::UniversalRegions;
 use crate::{BorrowckInferCtxt, polonius, renumber};
 
@@ -50,10 +50,9 @@ pub(crate) struct NllOutput<'tcx> {
 /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
 /// regions (e.g., region parameters) declared on the function. That set will need to be given to
 /// `compute_regions`.
-#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
+#[instrument(skip(infcx, body, promoted), level = "debug")]
 pub(crate) fn replace_regions_in_mir<'tcx>(
     infcx: &BorrowckInferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
 ) -> UniversalRegions<'tcx> {
@@ -62,7 +61,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
     debug!(?def);
 
     // Compute named region information. This also renumbers the inputs/outputs.
-    let universal_regions = UniversalRegions::new(infcx, def, param_env);
+    let universal_regions = UniversalRegions::new(infcx, def);
 
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
@@ -81,11 +80,9 @@ pub(crate) fn compute_regions<'a, 'tcx>(
     body: &Body<'tcx>,
     promoted: &IndexSlice<Promoted, Body<'tcx>>,
     location_table: &LocationTable,
-    param_env: ty::ParamEnv<'tcx>,
-    flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
+    flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
     move_data: &MoveData<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    upvars: &[&ty::CapturedPlace<'tcx>],
     consumer_options: Option<ConsumerOptions>,
 ) -> NllOutput<'tcx> {
     let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
@@ -96,41 +93,27 @@ pub(crate) fn compute_regions<'a, 'tcx>(
     let mut all_facts =
         (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
 
-    let universal_regions = Rc::new(universal_regions);
-
     let elements = Rc::new(DenseLocationMap::new(body));
 
     // Run the MIR type-checker.
     let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
         type_check::type_check(
             infcx,
-            param_env,
             body,
             promoted,
-            Rc::clone(&universal_regions),
+            universal_regions,
             location_table,
             borrow_set,
             &mut all_facts,
             flow_inits,
             move_data,
             Rc::clone(&elements),
-            upvars,
         );
 
     // Create the region inference context, taking ownership of the
     // region inference data that was contained in `infcx`, and the
     // base constraints generated by the type-check.
     let var_origins = infcx.get_region_var_origins();
-    let MirTypeckRegionConstraints {
-        placeholder_indices,
-        placeholder_index_to_region: _,
-        liveness_constraints,
-        mut outlives_constraints,
-        mut member_constraints,
-        universe_causes,
-        type_tests,
-    } = constraints;
-    let placeholder_indices = Rc::new(placeholder_indices);
 
     // If requested, emit legacy polonius facts.
     polonius::emit_facts(
@@ -140,31 +123,14 @@ pub(crate) fn compute_regions<'a, 'tcx>(
         body,
         borrow_set,
         move_data,
-        &universal_regions,
         &universal_region_relations,
     );
 
-    if let Some(guar) = universal_regions.tainted_by_errors() {
-        // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
-        // outlives bounds that we may end up checking.
-        outlives_constraints = Default::default();
-        member_constraints = Default::default();
-
-        // Also taint the entire scope.
-        infcx.set_tainted_by_errors(guar);
-    }
-
     let mut regioncx = RegionInferenceContext::new(
         infcx,
         var_origins,
-        universal_regions,
-        placeholder_indices,
+        constraints,
         universal_region_relations,
-        outlives_constraints,
-        member_constraints,
-        universe_causes,
-        type_tests,
-        liveness_constraints,
         elements,
     );
 
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index d1b65943199..f646beeecf7 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -88,6 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
             | StatementKind::Nop
             | StatementKind::Retag { .. }
             | StatementKind::Deinit(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs
index 6862eb13427..9fccc00bdaf 100644
--- a/compiler/rustc_borrowck/src/polonius/mod.rs
+++ b/compiler/rustc_borrowck/src/polonius/mod.rs
@@ -12,7 +12,6 @@ use crate::borrow_set::BorrowSet;
 use crate::facts::{AllFacts, PoloniusRegionVid};
 use crate::location::LocationTable;
 use crate::type_check::free_region_relations::UniversalRegionRelations;
-use crate::universal_regions::UniversalRegions;
 
 mod loan_invalidations;
 mod loan_kills;
@@ -32,7 +31,6 @@ pub(crate) fn emit_facts<'tcx>(
     body: &Body<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
     move_data: &MoveData<'_>,
-    universal_regions: &UniversalRegions<'_>,
     universal_region_relations: &UniversalRegionRelations<'_>,
 ) {
     let Some(all_facts) = all_facts else {
@@ -41,12 +39,7 @@ pub(crate) fn emit_facts<'tcx>(
     };
     let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
     emit_move_facts(all_facts, move_data, location_table, body);
-    emit_universal_region_facts(
-        all_facts,
-        borrow_set,
-        universal_regions,
-        universal_region_relations,
-    );
+    emit_universal_region_facts(all_facts, borrow_set, universal_region_relations);
     emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
     emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
 }
@@ -129,7 +122,6 @@ fn emit_move_facts(
 fn emit_universal_region_facts(
     all_facts: &mut AllFacts,
     borrow_set: &BorrowSet<'_>,
-    universal_regions: &UniversalRegions<'_>,
     universal_region_relations: &UniversalRegionRelations<'_>,
 ) {
     // 1: universal regions are modeled in Polonius as a pair:
@@ -138,9 +130,10 @@ fn emit_universal_region_facts(
     //   the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
     //   added to the existing number of loans, as if they succeeded them in the set.
     //
+    let universal_regions = &universal_region_relations.universal_regions;
     all_facts
         .universal_region
-        .extend(universal_regions.universal_regions().map(PoloniusRegionVid::from));
+        .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
     let borrow_count = borrow_set.len();
     debug!(
         "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
@@ -148,7 +141,7 @@ fn emit_universal_region_facts(
         borrow_count
     );
 
-    for universal_region in universal_regions.universal_regions() {
+    for universal_region in universal_regions.universal_regions_iter() {
         let universal_region_idx = universal_region.index();
         let placeholder_loan_idx = borrow_count + universal_region_idx;
         all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index 6b8dd1a49e7..ef3d6309c19 100644
--- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -23,7 +23,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         for region in self.regions() {
             if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin {
-                let classification = self.universal_regions.region_classification(region).unwrap();
+                let classification =
+                    self.universal_regions().region_classification(region).unwrap();
                 let outlived_by = self.universal_region_relations.regions_outlived_by(region);
                 writeln!(
                     out,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 7e317ea6554..0ddb4e110e3 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -31,11 +31,9 @@ use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
 use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
 use crate::nll::PoloniusOutput;
 use crate::region_infer::reverse_sccs::ReverseSccGraph;
-use crate::region_infer::values::{
-    LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
-};
-use crate::type_check::Locations;
+use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex};
 use crate::type_check::free_region_relations::UniversalRegionRelations;
+use crate::type_check::{Locations, MirTypeckRegionConstraints};
 use crate::universal_regions::UniversalRegions;
 
 mod dump_mir;
@@ -191,10 +189,6 @@ pub struct RegionInferenceContext<'tcx> {
     /// Type constraints that we check after solving.
     type_tests: Vec<TypeTest<'tcx>>,
 
-    /// Information about the universally quantified regions in scope
-    /// on this function.
-    universal_regions: Rc<UniversalRegions<'tcx>>,
-
     /// Information about how the universally quantified regions in
     /// scope on this function relate to one another.
     universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
@@ -399,21 +393,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn new(
         infcx: &BorrowckInferCtxt<'tcx>,
         var_infos: VarInfos,
-        universal_regions: Rc<UniversalRegions<'tcx>>,
-        placeholder_indices: Rc<PlaceholderIndices>,
+        constraints: MirTypeckRegionConstraints<'tcx>,
         universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-        mut outlives_constraints: OutlivesConstraintSet<'tcx>,
-        member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
-        universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
-        type_tests: Vec<TypeTest<'tcx>>,
-        liveness_constraints: LivenessValues,
         elements: Rc<DenseLocationMap>,
     ) -> Self {
-        debug!("universal_regions: {:#?}", universal_regions);
+        let universal_regions = &universal_region_relations.universal_regions;
+        let MirTypeckRegionConstraints {
+            placeholder_indices,
+            placeholder_index_to_region: _,
+            liveness_constraints,
+            mut outlives_constraints,
+            mut member_constraints,
+            universe_causes,
+            type_tests,
+        } = constraints;
+
+        debug!("universal_regions: {:#?}", universal_region_relations.universal_regions);
         debug!("outlives constraints: {:#?}", outlives_constraints);
         debug!("placeholder_indices: {:#?}", placeholder_indices);
         debug!("type tests: {:#?}", type_tests);
 
+        if let Some(guar) = universal_region_relations.universal_regions.tainted_by_errors() {
+            // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
+            // outlives bounds that we may end up checking.
+            outlives_constraints = Default::default();
+            member_constraints = Default::default();
+
+            // Also taint the entire scope.
+            infcx.set_tainted_by_errors(guar);
+        }
+
         // Create a RegionDefinition for each inference variable.
         let definitions: IndexVec<_, _> = var_infos
             .iter()
@@ -438,7 +447,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
 
         let member_constraints =
-            Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
+            Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r)));
 
         let mut result = Self {
             var_infos,
@@ -453,7 +462,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             universe_causes,
             scc_values,
             type_tests,
-            universal_regions,
             universal_region_relations,
         };
 
@@ -518,7 +526,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn init_free_and_bound_regions(&mut self) {
         // Update the names (if any)
         // This iterator has unstable order but we collect it all into an IndexVec
-        for (external_name, variable) in self.universal_regions.named_universal_regions() {
+        for (external_name, variable) in
+            self.universal_region_relations.universal_regions.named_universal_regions_iter()
+        {
             debug!(
                 "init_free_and_bound_regions: region {:?} has external name {:?}",
                 variable, external_name
@@ -562,7 +572,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ///
     /// (Panics if `r` is not a registered universal region.)
     pub(crate) fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
-        self.universal_regions.to_region_vid(r)
+        self.universal_regions().to_region_vid(r)
     }
 
     /// Returns an iterator over all the outlives constraints.
@@ -574,7 +584,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
     /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
     pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {
-        self.universal_regions.annotate(tcx, err)
+        self.universal_regions().annotate(tcx, err)
     }
 
     /// Returns `true` if the region `r` contains the point `p`.
@@ -686,7 +696,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         if outlives_requirements.is_empty() {
             (None, errors_buffer)
         } else {
-            let num_external_vids = self.universal_regions.num_global_and_external_regions();
+            let num_external_vids = self.universal_regions().num_global_and_external_regions();
             (
                 Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }),
                 errors_buffer,
@@ -989,7 +999,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // always be in the root universe.
         if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
             debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
-            let static_r = self.universal_regions.fr_static;
+            let static_r = self.universal_regions().fr_static;
             propagated_outlives_requirements.push(ClosureOutlivesRequirement {
                 subject,
                 outlived_free_region: static_r,
@@ -1032,8 +1042,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // avoid potential non-determinism we approximate this by requiring
             // T: '1 and T: '2.
             for upper_bound in non_local_ub {
-                debug_assert!(self.universal_regions.is_universal_region(upper_bound));
-                debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
+                debug_assert!(self.universal_regions().is_universal_region(upper_bound));
+                debug_assert!(!self.universal_regions().is_local_free_region(upper_bound));
 
                 let requirement = ClosureOutlivesRequirement {
                     subject,
@@ -1101,7 +1111,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // To do so, we simply check every candidate `u_r` for equality.
             self.scc_values
                 .universal_regions_outlived_by(r_scc)
-                .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
+                .filter(|&u_r| !self.universal_regions().is_local_free_region(u_r))
                 .find(|&u_r| self.eval_equal(u_r, r_vid))
                 .map(|u_r| ty::Region::new_var(tcx, u_r))
                 // In case we could not find a named region to map to,
@@ -1139,9 +1149,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         // Find the smallest universal region that contains all other
         // universal regions within `region`.
-        let mut lub = self.universal_regions.fr_fn_body;
+        let mut lub = self.universal_regions().fr_fn_body;
         let r_scc = self.constraint_sccs.scc(r);
-        let static_r = self.universal_regions.fr_static;
+        let static_r = self.universal_regions().fr_static;
         for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
             let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
             debug!(?ur, ?lub, ?new_lub);
@@ -1288,12 +1298,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!(
             "sup_region's value = {:?} universal={:?}",
             self.region_value_str(sup_region),
-            self.universal_regions.is_universal_region(sup_region),
+            self.universal_regions().is_universal_region(sup_region),
         );
         debug!(
             "sub_region's value = {:?} universal={:?}",
             self.region_value_str(sub_region),
-            self.universal_regions.is_universal_region(sub_region),
+            self.universal_regions().is_universal_region(sub_region),
         );
 
         let sub_region_scc = self.constraint_sccs.scc(sub_region);
@@ -1308,7 +1318,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 by super `{sup_region_scc:?}`, promoting to static",
             );
 
-            return self.eval_outlives(sup_region, self.universal_regions.fr_static);
+            return self.eval_outlives(sup_region, self.universal_regions().fr_static);
         }
 
         // Both the `sub_region` and `sup_region` consist of the union
@@ -1332,7 +1342,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Now we have to compare all the points in the sub region and make
         // sure they exist in the sup region.
 
-        if self.universal_regions.is_universal_region(sup_region) {
+        if self.universal_regions().is_universal_region(sup_region) {
             // Micro-opt: universal regions contain all points.
             debug!("super is universal and hence contains all points");
             return true;
@@ -1736,7 +1746,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2);
         let result = {
             r == fr2 || {
-                fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r)
+                fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r)
             }
         };
         debug!("provides_universal_region: result = {:?}", result);
@@ -1837,7 +1847,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             // A constraint like `'r: 'x` can come from our constraint
             // graph.
-            let fr_static = self.universal_regions.fr_static;
+            let fr_static = self.universal_regions().fr_static;
             let outgoing_edges_from_graph =
                 self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static);
 
@@ -1952,7 +1962,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 
     pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> {
-        self.universal_regions.as_ref()
+        &self.universal_region_relations.universal_regions
     }
 
     /// Tries to find the best constraint to blame for the fact that
@@ -2212,7 +2222,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
     /// Access to the region graph, built from the outlives constraints.
     pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> {
-        self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static)
+        self.constraint_graph.region_graph(&self.constraints, self.universal_regions().fr_static)
     }
 
     /// Returns whether the given region is considered live at all points: whether it is a
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index d676ce59cfe..993d5d86333 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -74,7 +74,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             debug!(?opaque_type_key, ?concrete_type);
 
             let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> =
-                vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)];
+                vec![(self.universal_regions().fr_static, infcx.tcx.lifetimes.re_static)];
 
             let opaque_type_key =
                 opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| {
@@ -88,12 +88,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                         // the same name and simplifies subsequent handling.
                         // See [rustc-dev-guide chapter] § "Semantic lifetime equality".
                         NllRegionVariableOrigin::FreeRegion => self
-                            .universal_regions
                             .universal_regions()
+                            .universal_regions_iter()
                             .filter(|&ur| {
                                 // See [rustc-dev-guide chapter] § "Closure restrictions".
                                 !matches!(
-                                    self.universal_regions.region_classification(ur),
+                                    self.universal_regions().region_classification(ur),
                                     Some(RegionClassification::External)
                                 )
                             })
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index cfd5a92787e..d0cfe572d08 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -45,8 +45,8 @@ impl RegionInferenceContext<'_> {
 
         let graph = self.constraint_sccs.reverse();
         let mut paired_scc_regions = self
-            .universal_regions
             .universal_regions()
+            .universal_regions_iter()
             .map(|region| (self.constraint_sccs.scc(region), region))
             .collect::<Vec<_>>();
         paired_scc_regions.sort();
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 519edfafda5..a16bce63839 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -258,10 +258,9 @@ impl PlaceholderIndices {
 /// Here, the variable `'0` would contain the free region `'a`,
 /// because (since it is returned) it must live for at least `'a`. But
 /// it would also contain various points from within the function.
-#[derive(Clone)]
 pub(crate) struct RegionValues<N: Idx> {
     elements: Rc<DenseLocationMap>,
-    placeholder_indices: Rc<PlaceholderIndices>,
+    placeholder_indices: PlaceholderIndices,
     points: SparseIntervalMatrix<N, PointIndex>,
     free_regions: SparseBitMatrix<N, RegionVid>,
 
@@ -277,7 +276,7 @@ impl<N: Idx> RegionValues<N> {
     pub(crate) fn new(
         elements: Rc<DenseLocationMap>,
         num_universal_regions: usize,
-        placeholder_indices: Rc<PlaceholderIndices>,
+        placeholder_indices: PlaceholderIndices,
     ) -> Self {
         let num_points = elements.num_points();
         let num_placeholders = placeholder_indices.len();
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index aee13ca8cd7..68b843d4d0d 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -132,7 +132,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
-        let param_env = self.param_env;
+        let param_env = self.infcx.param_env;
         let predicate = predicate.upcast(self.tcx());
         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             locations,
@@ -158,7 +158,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     where
         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
     {
-        let param_env = self.param_env;
+        let param_env = self.infcx.param_env;
         let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             location.to_locations(),
             category,
@@ -176,7 +176,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let tcx = self.tcx();
         if self.infcx.next_trait_solver() {
             let body = self.body;
-            let param_env = self.param_env;
+            let param_env = self.infcx.param_env;
             self.fully_perform_op(
                 location.to_locations(),
                 ConstraintCategory::Boring,
@@ -223,7 +223,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             Locations::All(span),
             ConstraintCategory::Boring,
-            self.param_env.and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }),
+            self.infcx
+                .param_env
+                .and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }),
         );
     }
 
@@ -250,7 +252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let mir_ty = self.normalize(mir_ty, Locations::All(span));
 
         let cause = ObligationCause::dummy_with_span(span);
-        let param_env = self.param_env;
+        let param_env = self.infcx.param_env;
         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             Locations::All(span),
             ConstraintCategory::Boring,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 6c86968389a..67915371b1f 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -37,7 +37,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
+    known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
     locations: Locations,
     span: Span,
     category: ConstraintCategory<'tcx>,
@@ -52,7 +52,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: ty::Region<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
+        known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
         locations: Locations,
         span: Span,
         category: ConstraintCategory<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 8e1faf025e2..ea965eb6545 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -1,5 +1,3 @@
-use std::rc::Rc;
-
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
 use rustc_hir::def::DefKind;
@@ -23,7 +21,7 @@ use crate::universal_regions::UniversalRegions;
 
 #[derive(Debug)]
 pub(crate) struct UniversalRegionRelations<'tcx> {
-    universal_regions: Rc<UniversalRegions<'tcx>>,
+    pub(crate) universal_regions: UniversalRegions<'tcx>,
 
     /// Stores the outlives relations that are known to hold from the
     /// implied bounds, in-scope where-clauses, and that sort of
@@ -46,7 +44,7 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
 pub(crate) struct CreateResult<'tcx> {
     pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
     pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
-    pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
+    pub(crate) known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
     pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
 }
 
@@ -54,7 +52,7 @@ pub(crate) fn create<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
-    universal_regions: Rc<UniversalRegions<'tcx>>,
+    universal_regions: UniversalRegions<'tcx>,
     constraints: &mut MirTypeckRegionConstraints<'tcx>,
 ) -> CreateResult<'tcx> {
     UniversalRegionRelationsBuilder {
@@ -184,7 +182,7 @@ impl UniversalRegionRelations<'_> {
 struct UniversalRegionRelationsBuilder<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    universal_regions: Rc<UniversalRegions<'tcx>>,
+    universal_regions: UniversalRegions<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 
@@ -220,7 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         //   region `'r`, all of which are provided by our caller
         let fr_static = self.universal_regions.fr_static;
         let fr_fn_body = self.universal_regions.fr_fn_body;
-        for fr in self.universal_regions.universal_regions() {
+        for fr in self.universal_regions.universal_regions_iter() {
             debug!("build: relating free region {:?} to itself and to 'static", fr);
             self.relate_universal_regions(fr, fr);
             self.relate_universal_regions(fr_static, fr);
@@ -236,7 +234,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             // In the new solver, normalize the type-outlives obligation assumptions.
             if self.infcx.next_trait_solver() {
                 match deeply_normalize(
-                    self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
+                    self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), param_env),
                     outlives,
                 ) {
                     Ok(normalized_outlives) => {
@@ -250,8 +248,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
 
             known_type_outlives_obligations.push(outlives);
         }
-        let known_type_outlives_obligations =
-            self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
 
         let unnormalized_input_output_tys = self
             .universal_regions
@@ -278,15 +274,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             if let Some(c) = constraints_unnorm {
                 constraints.push(c)
             }
-            let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
-                .param_env
-                .and(type_op::normalize::Normalize { value: ty })
-                .fully_perform(self.infcx, span)
-                .unwrap_or_else(|guar| TypeOpOutput {
-                    output: Ty::new_error(self.infcx.tcx, guar),
-                    constraints: None,
-                    error_info: None,
-                });
+            let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
+                param_env
+                    .and(type_op::normalize::Normalize { value: ty })
+                    .fully_perform(self.infcx, span)
+                    .unwrap_or_else(|guar| TypeOpOutput {
+                        output: Ty::new_error(self.infcx.tcx, guar),
+                        constraints: None,
+                        error_info: None,
+                    });
             if let Some(c) = constraints_normalize {
                 constraints.push(c)
             }
@@ -316,8 +312,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         // Add implied bounds from impl header.
         if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
             for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
-                let result: Result<_, ErrorGuaranteed> = self
-                    .param_env
+                let result: Result<_, ErrorGuaranteed> = param_env
                     .and(type_op::normalize::Normalize { value: ty })
                     .fully_perform(self.infcx, span);
                 let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
@@ -340,7 +335,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 &self.region_bound_pairs,
                 self.implicit_region_bound,
                 param_env,
-                known_type_outlives_obligations,
+                &known_type_outlives_obligations,
                 Locations::All(span),
                 span,
                 ConstraintCategory::Internal,
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 7effd5c5a68..bbe2b55d8c4 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -19,7 +19,7 @@ use tracing::{debug, instrument};
 
 use super::{Locations, TypeChecker};
 use crate::renumber::RegionCtxt;
-use crate::universal_regions::{DefiningTy, UniversalRegions};
+use crate::universal_regions::DefiningTy;
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// Check explicit closure signature annotation,
@@ -124,11 +124,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
     }
 
-    #[instrument(skip(self, body, universal_regions), level = "debug")]
+    #[instrument(skip(self, body), level = "debug")]
     pub(super) fn equate_inputs_and_outputs(
         &mut self,
         body: &Body<'tcx>,
-        universal_regions: &UniversalRegions<'tcx>,
         normalized_inputs_and_output: &[Ty<'tcx>],
     ) {
         let (&normalized_output_ty, normalized_input_tys) =
@@ -161,7 +160,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if let Some(mir_yield_ty) = body.yield_ty() {
             let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
             self.equate_normalized_input_or_output(
-                universal_regions.yield_ty.unwrap(),
+                self.universal_regions.yield_ty.unwrap(),
                 mir_yield_ty,
                 yield_span,
             );
@@ -170,7 +169,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if let Some(mir_resume_ty) = body.resume_ty() {
             let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
             self.equate_normalized_input_or_output(
-                universal_regions.resume_ty.unwrap(),
+                self.universal_regions.resume_ty.unwrap(),
                 mir_resume_ty,
                 yield_span,
             );
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 84fb36dd32a..20d19a53752 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -32,14 +32,14 @@ pub(super) fn generate<'a, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
     elements: &DenseLocationMap,
-    flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
+    flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
     move_data: &MoveData<'tcx>,
 ) {
     debug!("liveness::generate");
 
     let free_regions = regions_that_outlive_free_regions(
         typeck.infcx.num_region_vars(),
-        typeck.universal_regions,
+        &typeck.universal_regions,
         &typeck.constraints.outlives_constraints,
     );
     let (relevant_live_locals, boring_locals) =
@@ -107,7 +107,7 @@ fn regions_that_outlive_free_regions<'tcx>(
     let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);
 
     // Stack for the depth-first search. Start out with all the free regions.
-    let mut stack: Vec<_> = universal_regions.universal_regions().collect();
+    let mut stack: Vec<_> = universal_regions.universal_regions_iter().collect();
 
     // Set of all free regions, plus anything that outlives them. Initially
     // just contains the free regions.
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 72f6a605279..3ec36c16cbf 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -38,7 +38,7 @@ pub(super) fn trace<'a, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
     elements: &DenseLocationMap,
-    flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
+    flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
     move_data: &MoveData<'tcx>,
     relevant_live_locals: Vec<Local>,
     boring_locals: Vec<Local>,
@@ -113,7 +113,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
 
     /// Results of dataflow tracking which variables (and paths) have been
     /// initialized.
-    flow_inits: &'a mut ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>,
+    flow_inits: ResultsCursor<'b, 'tcx, MaybeInitializedPlaces<'b, 'tcx>>,
 
     /// Index indicating where each variable is assigned, used, or
     /// dropped.
@@ -608,7 +608,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
 
         value.visit_with(&mut for_liveness::FreeRegionsVisitor {
             tcx: typeck.tcx(),
-            param_env: typeck.param_env,
+            param_env: typeck.infcx.param_env,
             op: |r| {
                 let live_region_vid = typeck.universal_regions.to_region_vid(r);
 
@@ -621,6 +621,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
 
         match typeck
+            .infcx
             .param_env
             .and(DropckOutlives { dropped_ty })
             .fully_perform(typeck.infcx, DUMMY_SP)
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 0fe6a4b5fce..3a7ed711f68 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -118,17 +118,15 @@ mod relate_tys;
 /// - `elements` -- MIR region map
 pub(crate) fn type_check<'a, 'tcx>(
     infcx: &BorrowckInferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     promoted: &IndexSlice<Promoted, Body<'tcx>>,
-    universal_regions: Rc<UniversalRegions<'tcx>>,
+    universal_regions: UniversalRegions<'tcx>,
     location_table: &LocationTable,
     borrow_set: &BorrowSet<'tcx>,
     all_facts: &mut Option<AllFacts>,
-    flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
+    flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
     move_data: &MoveData<'tcx>,
     elements: Rc<DenseLocationMap>,
-    upvars: &[&ty::CapturedPlace<'tcx>],
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
     let mut constraints = MirTypeckRegionConstraints {
@@ -148,9 +146,9 @@ pub(crate) fn type_check<'a, 'tcx>(
         known_type_outlives_obligations,
     } = free_region_relations::create(
         infcx,
-        param_env,
+        infcx.param_env,
         implicit_region_bound,
-        Rc::clone(&universal_regions),
+        universal_regions,
         &mut constraints,
     );
 
@@ -158,29 +156,27 @@ pub(crate) fn type_check<'a, 'tcx>(
 
     let mut checker = TypeChecker {
         infcx,
-        param_env,
         last_span: body.span,
         body,
         user_type_annotations: &body.user_type_annotations,
-        region_bound_pairs: &region_bound_pairs,
+        region_bound_pairs,
         known_type_outlives_obligations,
         implicit_region_bound,
         reported_errors: Default::default(),
-        universal_regions: &universal_regions,
+        universal_regions: &universal_region_relations.universal_regions,
         location_table,
         all_facts,
         borrow_set,
         constraints: &mut constraints,
-        upvars,
     };
 
     checker.check_user_type_annotations();
 
-    let mut verifier = TypeVerifier::new(&mut checker, promoted);
+    let mut verifier = TypeVerifier { cx: &mut checker, promoted, last_span: body.span };
     verifier.visit_body(body);
 
     checker.typeck_mir(body);
-    checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output);
+    checker.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
     checker.check_signature_annotation(body);
 
     liveness::generate(&mut checker, body, &elements, flow_inits, move_data);
@@ -467,13 +463,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
 }
 
 impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
-    fn new(
-        cx: &'a mut TypeChecker<'b, 'tcx>,
-        promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
-    ) -> Self {
-        TypeVerifier { promoted, last_span: cx.body.span, cx }
-    }
-
     fn body(&self) -> &Body<'tcx> {
         self.cx.body
     }
@@ -837,14 +826,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 /// NLL region checking.
 struct TypeChecker<'a, 'tcx> {
     infcx: &'a BorrowckInferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     last_span: Span,
     body: &'a Body<'tcx>,
     /// User type annotations are shared between the main MIR and the MIR of
     /// all of the promoted items.
     user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
-    region_bound_pairs: &'a RegionBoundPairs<'tcx>,
-    known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
+    region_bound_pairs: RegionBoundPairs<'tcx>,
+    known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
     implicit_region_bound: ty::Region<'tcx>,
     reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
     universal_regions: &'a UniversalRegions<'tcx>,
@@ -852,7 +840,6 @@ struct TypeChecker<'a, 'tcx> {
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
-    upvars: &'a [&'a ty::CapturedPlace<'tcx>],
 }
 
 /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
@@ -1025,10 +1012,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         constraint_conversion::ConstraintConversion::new(
             self.infcx,
             self.universal_regions,
-            self.region_bound_pairs,
+            &self.region_bound_pairs,
             self.implicit_region_bound,
-            self.param_env,
-            self.known_type_outlives_obligations,
+            self.infcx.param_env,
+            &self.known_type_outlives_obligations,
             locations,
             locations.span(self.body),
             category,
@@ -1265,6 +1252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | StatementKind::Coverage(..)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
             StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
@@ -1527,7 +1515,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // The signature in this call can reference region variables,
                 // so erase them before calling a query.
                 let output_ty = self.tcx().erase_regions(sig.output());
-                if !output_ty.is_privately_uninhabited(self.tcx(), self.param_env) {
+                if !output_ty.is_privately_uninhabited(
+                    self.tcx(),
+                    self.infcx.typing_env(self.infcx.param_env),
+                ) {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             }
@@ -1737,7 +1728,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // `Sized` bound in no way depends on precise regions, so this
         // shouldn't affect `is_sized`.
         let erased_ty = tcx.erase_regions(ty);
-        if !erased_ty.is_sized(tcx, self.param_env) {
+        // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here.
+        if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) {
             // in current MIR construction, all non-control-flow rvalue
             // expressions evaluate through `as_temp` or `into` a return
             // slot or local, so to find all unsized rvalues it is enough
@@ -2629,8 +2621,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         let tcx = self.infcx.tcx;
+        let def = self.body.source.def_id().expect_local();
+        let upvars = tcx.closure_captures(def);
         let field =
-            path_utils::is_upvar_field_projection(tcx, self.upvars, borrowed_place.as_ref(), body);
+            path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), body);
         let category = if let Some(field) = field {
             ConstraintCategory::ClosureUpvar(field)
         } else {
@@ -2785,10 +2779,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             constraint_conversion::ConstraintConversion::new(
                 self.infcx,
                 self.universal_regions,
-                self.region_bound_pairs,
+                &self.region_bound_pairs,
                 self.implicit_region_bound,
-                self.param_env,
-                self.known_type_outlives_obligations,
+                self.infcx.param_env,
+                &self.known_type_outlives_obligations,
                 locations,
                 self.body.span,             // irrelevant; will be overridden.
                 ConstraintCategory::Boring, // same as above.
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index e2f3e065bc0..752b2bf1a24 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -522,7 +522,7 @@ impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_
     }
 
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.type_checker.param_env
+        self.type_checker.infcx.param_env
     }
 
     fn register_predicates(
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index b63144f560f..f1c23aa26a9 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -248,12 +248,8 @@ impl<'tcx> UniversalRegions<'tcx> {
     /// MIR -- that is, all the regions that appear in the function's
     /// signature. This will also compute the relationships that are
     /// known between those regions.
-    pub(crate) fn new(
-        infcx: &BorrowckInferCtxt<'tcx>,
-        mir_def: LocalDefId,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Self {
-        UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
+    pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self {
+        UniversalRegionsBuilder { infcx, mir_def }.build()
     }
 
     /// Given a reference to a closure type, extracts all the values
@@ -312,7 +308,7 @@ impl<'tcx> UniversalRegions<'tcx> {
 
     /// Returns an iterator over all the RegionVids corresponding to
     /// universally quantified free regions.
-    pub(crate) fn universal_regions(&self) -> impl Iterator<Item = RegionVid> {
+    pub(crate) fn universal_regions_iter(&self) -> impl Iterator<Item = RegionVid> {
         (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize)
     }
 
@@ -336,7 +332,7 @@ impl<'tcx> UniversalRegions<'tcx> {
     }
 
     /// Gets an iterator over all the early-bound regions that have names.
-    pub(crate) fn named_universal_regions<'s>(
+    pub(crate) fn named_universal_regions_iter<'s>(
         &'s self,
     ) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's {
         self.indices.indices.iter().map(|(&r, &v)| (r, v))
@@ -426,7 +422,6 @@ impl<'tcx> UniversalRegions<'tcx> {
 struct UniversalRegionsBuilder<'infcx, 'tcx> {
     infcx: &'infcx BorrowckInferCtxt<'tcx>,
     mir_def: LocalDefId,
-    param_env: ty::ParamEnv<'tcx>,
 }
 
 const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion;
@@ -435,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     fn build(self) -> UniversalRegions<'tcx> {
         debug!("build(mir_def={:?})", self.mir_def);
 
-        let param_env = self.param_env;
+        let param_env = self.infcx.param_env;
         debug!("build: param_env={:?}", param_env);
 
         assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index b686a8cf935..d46a1bd3d31 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -39,50 +39,10 @@ pub(crate) fn cfg_eval(
     let features = Some(features);
     CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id })
         .configure_annotatable(annotatable)
-        // Since the item itself has already been configured by the `InvocationCollector`,
-        // we know that fold result vector will contain exactly one element.
-        .unwrap()
 }
 
 struct CfgEval<'a>(StripUnconfigured<'a>);
 
-fn flat_map_annotatable(
-    vis: &mut impl MutVisitor,
-    annotatable: Annotatable,
-) -> Option<Annotatable> {
-    match annotatable {
-        Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item),
-        Annotatable::AssocItem(item, ctxt) => {
-            Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt))
-        }
-        Annotatable::ForeignItem(item) => {
-            vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
-        }
-        Annotatable::Stmt(stmt) => {
-            vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt)
-        }
-        Annotatable::Expr(mut expr) => {
-            vis.visit_expr(&mut expr);
-            Some(Annotatable::Expr(expr))
-        }
-        Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm),
-        Annotatable::ExprField(field) => {
-            vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField)
-        }
-        Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField),
-        Annotatable::GenericParam(param) => {
-            vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam)
-        }
-        Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
-        Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
-        Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
-        Annotatable::Crate(mut krate) => {
-            vis.visit_crate(&mut krate);
-            Some(Annotatable::Crate(krate))
-        }
-    }
-}
-
 fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
     struct CfgFinder;
 
@@ -106,14 +66,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
         Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
         Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
         Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
-        Annotatable::Arm(arm) => CfgFinder.visit_arm(arm),
-        Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field),
-        Annotatable::PatField(field) => CfgFinder.visit_pat_field(field),
-        Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param),
-        Annotatable::Param(param) => CfgFinder.visit_param(param),
-        Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field),
-        Annotatable::Variant(variant) => CfgFinder.visit_variant(variant),
-        Annotatable::Crate(krate) => CfgFinder.visit_crate(krate),
+        _ => unreachable!(),
     };
     res.is_break()
 }
@@ -123,11 +76,11 @@ impl CfgEval<'_> {
         self.0.configure(node)
     }
 
-    fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
+    fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable {
         // Tokenizing and re-parsing the `Annotatable` can have a significant
         // performance impact, so try to avoid it if possible
         if !has_cfg_or_cfg_attr(&annotatable) {
-            return Some(annotatable);
+            return annotatable;
         }
 
         // The majority of parsed attribute targets will never need to have early cfg-expansion
@@ -140,39 +93,6 @@ impl CfgEval<'_> {
         // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
         // process is lossless, so this process is invisible to proc-macros.
 
-        let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> =
-            match annotatable {
-                Annotatable::Item(_) => {
-                    |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
-                }
-                Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| {
-                    Ok(Annotatable::AssocItem(
-                        parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
-                        AssocCtxt::Trait,
-                    ))
-                },
-                Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| {
-                    Ok(Annotatable::AssocItem(
-                        parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
-                        AssocCtxt::Impl,
-                    ))
-                },
-                Annotatable::ForeignItem(_) => |parser| {
-                    Ok(Annotatable::ForeignItem(
-                        parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(),
-                    ))
-                },
-                Annotatable::Stmt(_) => |parser| {
-                    Ok(Annotatable::Stmt(P(parser
-                        .parse_stmt_without_recovery(false, ForceCollect::Yes)?
-                        .unwrap())))
-                },
-                Annotatable::Expr(_) => {
-                    |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?))
-                }
-                _ => unreachable!(),
-            };
-
         // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
         // to `None`-delimited groups containing the corresponding tokens. This
         // is normally delayed until the proc-macro server actually needs to
@@ -191,19 +111,56 @@ impl CfgEval<'_> {
         // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
         // to the captured `AttrTokenStream` (specifically, we capture
         // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
+        //
+        // After that we have our re-parsed `AttrTokenStream`, recursively configuring
+        // our attribute target will correctly configure the tokens as well.
         let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None);
         parser.capture_cfg = true;
-        match parse_annotatable_with(&mut parser) {
-            Ok(a) => annotatable = a,
+        let res: PResult<'_, Annotatable> = try {
+            match annotatable {
+                Annotatable::Item(_) => {
+                    let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
+                    Annotatable::Item(self.flat_map_item(item).pop().unwrap())
+                }
+                Annotatable::AssocItem(_, AssocCtxt::Trait) => {
+                    let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap();
+                    Annotatable::AssocItem(
+                        self.flat_map_assoc_item(item, AssocCtxt::Trait).pop().unwrap(),
+                        AssocCtxt::Trait,
+                    )
+                }
+                Annotatable::AssocItem(_, AssocCtxt::Impl) => {
+                    let item = parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap();
+                    Annotatable::AssocItem(
+                        self.flat_map_assoc_item(item, AssocCtxt::Impl).pop().unwrap(),
+                        AssocCtxt::Impl,
+                    )
+                }
+                Annotatable::ForeignItem(_) => {
+                    let item = parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap();
+                    Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
+                }
+                Annotatable::Stmt(_) => {
+                    let stmt =
+                        parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap();
+                    Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap()))
+                }
+                Annotatable::Expr(_) => {
+                    let mut expr = parser.parse_expr_force_collect()?;
+                    self.visit_expr(&mut expr);
+                    Annotatable::Expr(expr)
+                }
+                _ => unreachable!(),
+            }
+        };
+
+        match res {
+            Ok(ann) => ann,
             Err(err) => {
                 err.emit();
-                return Some(annotatable);
+                annotatable
             }
         }
-
-        // Now that we have our re-parsed `AttrTokenStream`, recursively configuring
-        // our attribute target will correctly configure the tokens as well.
-        flat_map_annotatable(self, annotatable)
     }
 }
 
@@ -247,10 +204,10 @@ impl MutVisitor for CfgEval<'_> {
     fn flat_map_assoc_item(
         &mut self,
         item: P<ast::AssocItem>,
-        _ctxt: AssocCtxt,
+        ctxt: AssocCtxt,
     ) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let item = configure!(self, item);
-        mut_visit::walk_flat_map_item(self, item)
+        mut_visit::walk_flat_map_assoc_item(self, item, ctxt)
     }
 
     fn flat_map_foreign_item(
@@ -258,7 +215,7 @@ impl MutVisitor for CfgEval<'_> {
         foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
         let foreign_item = configure!(self, foreign_item);
-        mut_visit::walk_flat_map_item(self, foreign_item)
+        mut_visit::walk_flat_map_foreign_item(self, foreign_item)
     }
 
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 95348453308..b2048c534a4 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -1,6 +1,6 @@
 // Code that generates a test runner to run all the tests in a crate
 
-use std::{iter, mem};
+use std::mem;
 
 use rustc_ast as ast;
 use rustc_ast::entry::EntryPointType;
@@ -19,7 +19,7 @@ use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
 use rustc_span::symbol::{Ident, Symbol, sym};
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::spec::PanicStrategy;
-use smallvec::{SmallVec, smallvec};
+use smallvec::smallvec;
 use thin_vec::{ThinVec, thin_vec};
 use tracing::debug;
 
@@ -129,8 +129,9 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         c.items.push(mk_main(&mut self.cx));
     }
 
-    fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        let item = &mut *i;
+    fn visit_item(&mut self, item: &mut P<ast::Item>) {
+        let item = &mut **item;
+
         if let Some(name) = get_test_name(&item) {
             debug!("this is a test item");
 
@@ -144,13 +145,20 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
             item.kind
         {
             let prev_tests = mem::take(&mut self.tests);
-            walk_item_kind(&mut item.kind, item.span, item.id, self);
+            walk_item_kind(
+                &mut item.kind,
+                item.span,
+                item.id,
+                &mut item.ident,
+                &mut item.vis,
+                (),
+                self,
+            );
             self.add_test_cases(item.id, span, prev_tests);
         } else {
             // But in those cases, we emit a lint to warn the user of these missing tests.
             walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
         }
-        smallvec![i]
     }
 }
 
@@ -190,40 +198,30 @@ struct EntryPointCleaner<'a> {
 }
 
 impl<'a> MutVisitor for EntryPointCleaner<'a> {
-    fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+    fn visit_item(&mut self, item: &mut P<ast::Item>) {
         self.depth += 1;
-        let item = walk_flat_map_item(self, i).expect_one("noop did something");
+        ast::mut_visit::walk_item(self, item);
         self.depth -= 1;
 
         // Remove any #[rustc_main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
-        let item = match entry_point_type(&item, self.depth == 0) {
+        match entry_point_type(&item, self.depth == 0) {
             EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
-                item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
-                    let allow_dead_code = attr::mk_attr_nested_word(
-                        &self.sess.psess.attr_id_generator,
-                        ast::AttrStyle::Outer,
-                        ast::Safety::Default,
-                        sym::allow,
-                        sym::dead_code,
-                        self.def_site,
-                    );
-                    let attrs = attrs
-                        .into_iter()
-                        .filter(|attr| {
-                            !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)
-                        })
-                        .chain(iter::once(allow_dead_code))
-                        .collect();
-
-                    ast::Item { id, ident, attrs, kind, vis, span, tokens }
-                })
+                let allow_dead_code = attr::mk_attr_nested_word(
+                    &self.sess.psess.attr_id_generator,
+                    ast::AttrStyle::Outer,
+                    ast::Safety::Default,
+                    sym::allow,
+                    sym::dead_code,
+                    self.def_site,
+                );
+                item.attrs
+                    .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start));
+                item.attrs.push(allow_dead_code);
             }
-            EntryPointType::None | EntryPointType::OtherMain => item,
+            EntryPointType::None | EntryPointType::OtherMain => {}
         };
-
-        smallvec![item]
     }
 }
 
@@ -284,7 +282,7 @@ fn generate_test_harness(
 /// Most of the Ident have the usual def-site hygiene for the AST pass. The
 /// exception is the `test_const`s. These have a syntax context that has two
 /// opaque marks: one from the expansion of `test` or `test_case`, and one
-/// generated  in `TestHarnessGenerator::flat_map_item`. When resolving this
+/// generated  in `TestHarnessGenerator::visit_item`. When resolving this
 /// identifier after failing to find a matching identifier in the root module
 /// we remove the outer mark, and try resolving at its def-site, which will
 /// then resolve to `test_const`.
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 2f13b0b9cb8..5b3f2a91207 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -38,6 +38,11 @@ local-rebuild = true
 codegen-backends = ["cranelift"]
 deny-warnings = false
 verbose-tests = false
+# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is
+# disabled bootstrap will crash trying to copy llvm tools for the bootstrap
+# compiler.
+llvm_tools = false
+
 EOF
 popd
 
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index f647ee36c48..7dd2139cf90 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
         let instance = ty::Instance::expect_resolve(
             fx.tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             def_id,
             fn_args,
             source_info.span,
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index da3818ca25e..70b7d92ce15 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::InlineAsmMacro;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::layout::FnAbiOf;
+use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 
 use crate::constant::ConstantCx;
@@ -666,7 +666,7 @@ fn codegen_stmt<'tcx>(
                             let func_ref = fx.get_function_ref(
                                 Instance::resolve_for_fn_ptr(
                                     fx.tcx,
-                                    ParamEnv::reveal_all(),
+                                    ty::TypingEnv::fully_monomorphized(),
                                     def_id,
                                     args,
                                 )
@@ -841,14 +841,18 @@ fn codegen_stmt<'tcx>(
                     lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
                 }
                 Rvalue::NullaryOp(ref null_op, ty) => {
-                    assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
+                    assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env()));
                     let layout = fx.layout_of(fx.monomorphize(ty));
                     let val = match null_op {
                         NullOp::SizeOf => layout.size.bytes(),
                         NullOp::AlignOf => layout.align.abi.bytes(),
                         NullOp::OffsetOf(fields) => fx
                             .tcx
-                            .offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter())
+                            .offset_of_subfield(
+                                ty::TypingEnv::fully_monomorphized(),
+                                layout,
+                                fields.iter(),
+                            )
                             .bytes(),
                         NullOp::UbChecks => {
                             let val = fx.tcx.sess.ub_checks();
@@ -920,6 +924,7 @@ fn codegen_stmt<'tcx>(
         | StatementKind::FakeRead(..)
         | StatementKind::Retag { .. }
         | StatementKind::PlaceMention(..)
+        | StatementKind::BackwardIncompatibleDropHint { .. }
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::Coverage { .. } => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 27e71b92561..c663fa32965 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -103,11 +103,11 @@ fn clif_pair_type_from_ty<'tcx>(
 
 /// Is a pointer to this type a wide ptr?
 pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    if ty.is_sized(tcx, ParamEnv::reveal_all()) {
+    if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) {
         return false;
     }
 
-    let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all());
+    let tail = tcx.struct_tail_for_codegen(ty, ty::TypingEnv::fully_monomorphized());
     match tail.kind() {
         ty::Foreign(..) => false,
         ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
@@ -339,9 +339,9 @@ impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        ParamEnv::reveal_all()
+impl<'tcx> layout::HasTypingEnv<'tcx> for FunctionCx<'_, '_, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
     }
 }
 
@@ -358,7 +358,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
     {
         self.instance.instantiate_mir_and_normalize_erasing_regions(
             self.tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             ty::EarlyBinder::bind(value),
         )
     }
@@ -497,9 +497,9 @@ impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
     }
 }
 
-impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        ParamEnv::reveal_all()
+impl<'tcx> layout::HasTypingEnv<'tcx> for RevealAllLayoutCx<'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index ab78584332a..abe6085b04f 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -78,7 +78,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
     let cv = fx.monomorphize(constant.const_);
     // This cannot fail because we checked all required_consts in advance.
     let val = cv
-        .eval(fx.tcx, ty::ParamEnv::reveal_all(), constant.span)
+        .eval(fx.tcx, ty::TypingEnv::fully_monomorphized(), constant.span)
         .expect("erroneous constant missed by mono item collection");
     (val, cv.ty())
 }
@@ -265,8 +265,13 @@ fn data_id_for_static(
         assert!(!definition);
         assert!(!tcx.is_mutable_static(def_id));
 
-        let ty = instance.ty(tcx, ParamEnv::reveal_all());
-        let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
+        let ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized());
+        let align = tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
+            .unwrap()
+            .align
+            .pref
+            .bytes();
 
         let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
             || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
@@ -578,6 +583,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         | StatementKind::PlaceMention(..)
                         | StatementKind::Coverage(_)
                         | StatementKind::ConstEvalCounter
+                        | StatementKind::BackwardIncompatibleDropHint { .. }
                         | StatementKind::Nop => {}
                     }
                 }
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 9025ea97b81..f3a8623e216 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -210,7 +210,7 @@ impl DebugContext {
 
         type_names::push_generic_params(
             tcx,
-            tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args),
             &mut name,
         );
 
@@ -275,8 +275,10 @@ impl DebugContext {
         let span = tcx.def_span(def_id);
         let (file_id, line, _column) = self.get_span_loc(tcx, span, span);
 
-        let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::ParamEnv::reveal_all());
-        let static_layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(static_type)).unwrap();
+        let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::TypingEnv::fully_monomorphized());
+        let static_layout = tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(static_type))
+            .unwrap();
         // FIXME use the actual type layout
         let type_id = self.debug_type(tcx, type_dbg, static_type);
 
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index a3f816f70a9..0df1a30fc0a 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -92,7 +92,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
                 if let ty::FnDef(def_id, args) = *const_.ty().kind() {
                     let instance = ty::Instance::resolve_for_fn_ptr(
                         fx.tcx,
-                        ty::ParamEnv::reveal_all(),
+                        ty::TypingEnv::fully_monomorphized(),
                         def_id,
                         args,
                     )
@@ -227,11 +227,11 @@ pub(crate) fn codegen_naked_asm<'tcx>(
             InlineAsmOperand::Const { ref value } => {
                 let cv = instance.instantiate_mir_and_normalize_erasing_regions(
                     tcx,
-                    ty::ParamEnv::reveal_all(),
+                    ty::TypingEnv::fully_monomorphized(),
                     ty::EarlyBinder::bind(value.const_),
                 );
                 let const_value = cv
-                    .eval(tcx, ty::ParamEnv::reveal_all(), value.span)
+                    .eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span)
                     .expect("erroneous constant missed by mono item collection");
 
                 let value = rustc_codegen_ssa::common::asm_const_to_str(
@@ -250,13 +250,13 @@ pub(crate) fn codegen_naked_asm<'tcx>(
 
                 let const_ = instance.instantiate_mir_and_normalize_erasing_regions(
                     tcx,
-                    ty::ParamEnv::reveal_all(),
+                    ty::TypingEnv::fully_monomorphized(),
                     ty::EarlyBinder::bind(value.const_),
                 );
                 if let ty::FnDef(def_id, args) = *const_.ty().kind() {
                     let instance = ty::Instance::resolve_for_fn_ptr(
                         tcx,
-                        ty::ParamEnv::reveal_all(),
+                        ty::TypingEnv::fully_monomorphized(),
                         def_id,
                         args,
                     )
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 1e2e41b3122..3318c0797ec 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -20,7 +20,7 @@ mod simd;
 use cranelift_codegen::ir::AtomicRmwOp;
 use rustc_middle::ty;
 use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement};
+use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{Symbol, sym};
@@ -453,11 +453,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
             fx.bcx.ins().trap(TrapCode::user(2).unwrap());
             return Ok(());
         }
-        sym::likely | sym::unlikely => {
-            intrinsic_args!(fx, args => (a); intrinsic);
-
-            ret.write_cvalue(fx, a);
-        }
         sym::breakpoint => {
             intrinsic_args!(fx, args => (); intrinsic);
 
@@ -687,7 +682,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             if let Some(requirement) = requirement {
                 let do_panic = !fx
                     .tcx
-                    .check_validity_requirement((requirement, fx.param_env().and(ty)))
+                    .check_validity_requirement((
+                        requirement,
+                        ty::TypingEnv::fully_monomorphized().as_query_input(ty),
+                    ))
                     .expect("expect to have layout during codegen");
 
                 if do_panic {
@@ -746,7 +744,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             let const_val = fx
                 .tcx
-                .const_eval_instance(ParamEnv::reveal_all(), instance, source_info.span)
+                .const_eval_instance(
+                    ty::TypingEnv::fully_monomorphized(),
+                    instance,
+                    source_info.span,
+                )
                 .unwrap();
             let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty);
             ret.write_cvalue(fx, val);
@@ -1267,6 +1269,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
             );
         }
 
+        sym::cold_path => {
+            // This is a no-op. The intrinsic is just a hint to the optimizer.
+            // We still have an impl here to avoid it being turned into a call.
+        }
+
         // Unimplemented intrinsics must have a fallback body. The fallback body is obtained
         // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`.
         _ => {
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index b506b1f5731..e6f6ae30581 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -98,7 +98,7 @@ mod prelude {
     pub(crate) use rustc_middle::mir::{self, *};
     pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
     pub(crate) use rustc_middle::ty::{
-        self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy,
+        self, FloatTy, Instance, InstanceKind, IntTy, Ty, TyCtxt, UintTy,
     };
     pub(crate) use rustc_span::Span;
 
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index df92bc58bf5..2ee4ff5cec7 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -49,7 +49,7 @@ pub(crate) fn maybe_create_entry_wrapper(
         // regions must appear in the argument
         // listing.
         let main_ret_ty = tcx.normalize_erasing_regions(
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             main_ret_ty.no_bound_vars().unwrap(),
         );
 
@@ -113,7 +113,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                     .unwrap();
                 let report = Instance::expect_resolve(
                     tcx,
-                    ParamEnv::reveal_all(),
+                    ty::TypingEnv::fully_monomorphized(),
                     report.def_id,
                     tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
                     DUMMY_SP,
@@ -139,7 +139,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                 let start_def_id = tcx.require_lang_item(LangItem::Start, None);
                 let start_instance = Instance::expect_resolve(
                     tcx,
-                    ParamEnv::reveal_all(),
+                    ty::TypingEnv::fully_monomorphized(),
                     start_def_id,
                     tcx.mk_args(&[main_ret_ty.into()]),
                     DUMMY_SP,
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 336934354e1..2843e5bbdfb 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -3,6 +3,7 @@
 //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize`
 
 use rustc_codegen_ssa::base::validate_trivial_unsize;
+use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 
 use crate::base::codegen_panic_nounwind;
@@ -23,7 +24,7 @@ pub(crate) fn unsized_info<'tcx>(
     old_info: Option<Value>,
 ) -> Value {
     let (source, target) =
-        fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all());
+        fx.tcx.struct_lockstep_tails_for_codegen(source, target, fx.typing_env());
     match (&source.kind(), &target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => fx.bcx.ins().iconst(
             fx.pointer_type,
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 900d7e69714..6676e684ca0 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -4,6 +4,7 @@ use cranelift_codegen::entity::EntityRef;
 use cranelift_codegen::ir::immediates::Offset32;
 use cranelift_frontend::Variable;
 use rustc_middle::ty::FnSig;
+use rustc_middle::ty::layout::HasTypingEnv;
 
 use crate::prelude::*;
 
@@ -884,19 +885,17 @@ pub(crate) fn assert_assignable<'tcx>(
             assert_assignable(fx, *a, *b, limit - 1);
         }
         (ty::FnPtr(..), ty::FnPtr(..)) => {
-            let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
-                ParamEnv::reveal_all(),
-                from_ty.fn_sig(fx.tcx),
-            );
+            let from_sig = fx
+                .tcx
+                .normalize_erasing_late_bound_regions(fx.typing_env(), from_ty.fn_sig(fx.tcx));
             let FnSig {
                 inputs_and_output: types_from,
                 c_variadic: c_variadic_from,
                 safety: unsafety_from,
                 abi: abi_from,
             } = from_sig;
-            let to_sig = fx
-                .tcx
-                .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx));
+            let to_sig =
+                fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to_ty.fn_sig(fx.tcx));
             let FnSig {
                 inputs_and_output: types_to,
                 c_variadic: c_variadic_to,
@@ -932,9 +931,8 @@ pub(crate) fn assert_assignable<'tcx>(
         (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => {
             // FIXME(dyn-star): Do the right thing with DynKinds
             for (from, to) in from_traits.iter().zip(to_traits) {
-                let from =
-                    fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from);
-                let to = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to);
+                let from = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), from);
+                let to = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to);
                 assert_eq!(
                     from, to,
                     "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}",
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index e6ae7cf174d..9a142326ad1 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -24,9 +24,9 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers,
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
 };
-use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::call::FnAbi;
@@ -2319,9 +2319,9 @@ impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> {
     }
 }
 
-impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        self.cx.param_env()
+impl<'tcx> HasTypingEnv<'tcx> for Builder<'_, '_, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.cx.typing_env()
     }
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index 07c7a54de1c..6dc2f4ed668 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -215,7 +215,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         let gcc_type = if nested {
             self.type_i8()
         } else {
-            let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+            let ty = instance.ty(self.tcx, ty::TypingEnv::fully_monomorphized());
             self.layout_of(ty).gcc_type(self)
         };
 
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 707b35967a6..3846d025537 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -11,10 +11,10 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError,
+    FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
     LayoutOfHelpers,
 };
-use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::source_map::respan;
 use rustc_span::{DUMMY_SP, Span};
@@ -144,7 +144,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
         supports_f128_type: bool,
     ) -> Self {
         let create_type = |ctype, rust_type| {
-            let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap();
+            let layout = tcx
+                .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type))
+                .unwrap();
             let align = layout.align.abi.bytes();
             #[cfg(feature = "master")]
             {
@@ -459,7 +461,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
             Some(def_id) if !wants_msvc_seh(self.sess()) => {
                 let instance = ty::Instance::expect_resolve(
                     tcx,
-                    ty::ParamEnv::reveal_all(),
+                    self.typing_env(),
                     def_id,
                     ty::List::empty(),
                     DUMMY_SP,
@@ -583,9 +585,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        ParamEnv::reveal_all()
+impl<'tcx, 'gcc> HasTypingEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
     }
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index 5d8c5c199b1..6aeb656c1ab 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -113,15 +113,15 @@ fn make_mir_scope<'gcc, 'tcx>(
     let scope_data = &mir.source_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
         make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent);
-        debug_context.scopes[parent]
+        debug_context.scopes[parent].unwrap()
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = DebugScope {
+        debug_context.scopes[scope] = Some(DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope]
-        };
+            ..debug_context.scopes[scope].unwrap()
+        });
         instantiated.insert(scope);
         return;
     };
@@ -130,7 +130,7 @@ fn make_mir_scope<'gcc, 'tcx>(
         if !vars.contains(scope) && scope_data.inlined.is_none() {
             // Do not create a DIScope if there are no variables defined in this
             // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-            debug_context.scopes[scope] = parent_scope;
+            debug_context.scopes[scope] = Some(parent_scope);
             instantiated.insert(scope);
             return;
         }
@@ -157,12 +157,12 @@ fn make_mir_scope<'gcc, 'tcx>(
     // TODO(tempdragon): dbg_scope: Add support for scope extension here.
     inlined_at.or(p_inlined_at);
 
-    debug_context.scopes[scope] = DebugScope {
+    debug_context.scopes[scope] = Some(DebugScope {
         dbg_scope,
         inlined_at,
         file_start_pos: loc.file.start_pos,
         file_end_pos: loc.file.end_position(),
-    };
+    });
     instantiated.insert(scope);
 }
 
@@ -232,12 +232,12 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = DebugScope {
+        let empty_scope = Some(DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        };
+        });
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()),
             inlined_function_scopes: Default::default(),
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index 5ca440f4c9b..02b760dc733 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -5,7 +5,7 @@
 use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp};
-use rustc_middle::ty::{ParamEnv, Ty};
+use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::Endian;
 use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
 use rustc_target::spec;
@@ -380,7 +380,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         let overflow_field = self.context.new_field(self.location, self.bool_type, "overflow");
 
         let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]);
-        let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap();
+        let layout = self
+            .tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ret_ty))
+            .unwrap();
 
         let arg_abi = ArgAbi { layout, mode: PassMode::Direct(ArgAttributes::new()) };
         let mut fn_abi = FnAbi {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index b0298a35cb0..69326f409bb 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -21,7 +21,7 @@ use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, MiscCodegenMethods};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::LayoutOf;
 #[cfg(feature = "master")]
-use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv};
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{Span, Symbol, sym};
 use rustc_target::abi::HasDataLayout;
@@ -107,7 +107,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
         span: Span,
     ) -> Result<(), Instance<'tcx>> {
         let tcx = self.tcx;
-        let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+        let callee_ty = instance.ty(tcx, self.typing_env());
 
         let (def_id, fn_args) = match *callee_ty.kind() {
             ty::FnDef(def_id, fn_args) => (def_id, fn_args),
@@ -115,7 +115,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
         };
 
         let sig = callee_ty.fn_sig(tcx);
-        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = tcx.item_name(def_id);
@@ -139,8 +139,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                 )
             }
-            sym::likely => self.expect(args[0].immediate(), true),
-            sym::unlikely => self.expect(args[0].immediate(), false),
             sym::is_val_statically_known => {
                 let a = args[0].immediate();
                 let builtin = self.context.get_builtin_function("__builtin_constant_p");
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 43dbfafa871..604678a9af4 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -55,8 +55,10 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     }
 
     let tcx = bx.tcx();
-    let sig =
-        tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
+    let sig = tcx.normalize_erasing_late_bound_regions(
+        ty::TypingEnv::fully_monomorphized(),
+        callee_ty.fn_sig(tcx),
+    );
     let arg_tys = sig.inputs();
 
     if name == sym::simd_select_bitmask {
@@ -478,7 +480,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         match *in_elem.kind() {
             ty::RawPtr(p_ty, _) => {
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
-                    bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
+                    bx.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
                 });
                 require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
@@ -493,7 +495,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         match *out_elem.kind() {
             ty::RawPtr(p_ty, _) => {
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
-                    bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
+                    bx.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
                 });
                 require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index b7b282bf2a6..239902df7f0 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 
 use crate::context::CodegenCx;
@@ -27,11 +27,8 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
         // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out
         // the gcc type from the actual evaluated initializer.
-        let ty = if nested {
-            self.tcx.types.unit
-        } else {
-            instance.ty(self.tcx, ty::ParamEnv::reveal_all())
-        };
+        let ty =
+            if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) };
         let gcc_type = self.layout_of(ty).gcc_type(self);
 
         let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index ac76b781218..b5bb7630ca6 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
     TyAndLayout,
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
@@ -81,9 +81,9 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.cx.param_env()
+impl<'tcx> ty::layout::HasTypingEnv<'tcx> for Builder<'_, '_, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.cx.typing_env()
     }
 }
 
@@ -472,7 +472,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     #[instrument(level = "trace", skip(self))]
     fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> {
         if place.layout.is_unsized() {
-            let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.param_env());
+            let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.typing_env());
             if matches!(tail.kind(), ty::Foreign(..)) {
                 // Unsized locals and, at least conceptually, even unsized arguments must be copied
                 // around, which requires dynamically determining their size. Therefore, we cannot
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index dcea9d3b391..e0a2de3366c 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -5,7 +5,7 @@
 //! closure.
 
 use rustc_codegen_ssa::common;
-use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 use tracing::debug;
 
@@ -28,12 +28,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
     }
 
     let sym = tcx.symbol_name(instance).name;
-    debug!(
-        "get_fn({:?}: {:?}) => {}",
-        instance,
-        instance.ty(cx.tcx(), ty::ParamEnv::reveal_all()),
-        sym
-    );
+    debug!("get_fn({:?}: {:?}) => {}", instance, instance.ty(cx.tcx(), cx.typing_env()), sym);
 
     let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
 
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 7ab4f45cd73..6f5ffbb4b34 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -13,8 +13,8 @@ use rustc_middle::mir::interpret::{
     read_target_uint,
 };
 use rustc_middle::mir::mono::MonoItem;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Instance};
+use rustc_middle::ty::Instance;
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::Lto;
 use tracing::{debug, instrument, trace};
@@ -244,7 +244,7 @@ impl<'ll> CodegenCx<'ll, '_> {
         let llty = if nested {
             self.type_i8()
         } else {
-            let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+            let ty = instance.ty(self.tcx, self.typing_env());
             trace!(?ty);
             self.layout_of(ty).llvm_type(self)
         };
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 3a7c7efe03b..841c110b3c8 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -15,7 +15,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry;
 use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -658,7 +658,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let llfn = match tcx.lang_items().eh_personality() {
             Some(def_id) if name.is_none() => self.get_fn_addr(ty::Instance::expect_resolve(
                 tcx,
-                ty::ParamEnv::reveal_all(),
+                self.typing_env(),
                 def_id,
                 ty::List::empty(),
                 DUMMY_SP,
@@ -1162,9 +1162,9 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for CodegenCx<'_, 'tcx> {
     }
 }
 
-impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        ty::ParamEnv::reveal_all()
+impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 0f1909486ec..07bd0f4d1c1 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -6,10 +6,10 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_index::Idx;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{Body, SourceScope};
-use rustc_middle::ty::layout::FnAbiOf;
+use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
-use rustc_span::BytePos;
+use rustc_span::{BytePos, hygiene};
 
 use super::metadata::file_metadata;
 use super::utils::DIB;
@@ -85,15 +85,23 @@ fn make_mir_scope<'ll, 'tcx>(
             discriminators,
             parent,
         );
-        debug_context.scopes[parent]
+        if let Some(parent_scope) = debug_context.scopes[parent] {
+            parent_scope
+        } else {
+            // If the parent scope could not be represented then no children
+            // can be either.
+            debug_context.scopes[scope] = None;
+            instantiated.insert(scope);
+            return;
+        }
     } else {
         // The root is the function itself.
         let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
-        debug_context.scopes[scope] = DebugScope {
+        debug_context.scopes[scope] = Some(DebugScope {
             file_start_pos: file.start_pos,
             file_end_pos: file.end_position(),
-            ..debug_context.scopes[scope]
-        };
+            ..debug_context.scopes[scope].unwrap()
+        });
         instantiated.insert(scope);
         return;
     };
@@ -104,7 +112,7 @@ fn make_mir_scope<'ll, 'tcx>(
     {
         // Do not create a DIScope if there are no variables defined in this
         // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
-        debug_context.scopes[scope] = parent_scope;
+        debug_context.scopes[scope] = Some(parent_scope);
         instantiated.insert(scope);
         return;
     }
@@ -118,7 +126,7 @@ fn make_mir_scope<'ll, 'tcx>(
             // if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
             let callee = cx.tcx.instantiate_and_normalize_erasing_regions(
                 instance.args,
-                ty::ParamEnv::reveal_all(),
+                cx.typing_env(),
                 ty::EarlyBinder::bind(callee),
             );
             debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| {
@@ -137,14 +145,20 @@ fn make_mir_scope<'ll, 'tcx>(
         },
     };
 
-    let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
-        // FIXME(eddyb) this doesn't account for the macro-related
-        // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
+    let mut debug_scope = Some(DebugScope {
+        dbg_scope,
+        inlined_at: parent_scope.inlined_at,
+        file_start_pos: loc.file.start_pos,
+        file_end_pos: loc.file.end_position(),
+    });
+
+    if let Some((_, callsite_span)) = scope_data.inlined {
+        let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span);
         let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
         let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
 
         // NB: In order to produce proper debug info for variables (particularly
-        // arguments) in multiply-inline functions, LLVM expects to see a single
+        // arguments) in multiply-inlined functions, LLVM expects to see a single
         // DILocalVariable with multiple different DILocations in the IR. While
         // the source information for each DILocation would be identical, their
         // inlinedAt attributes will be unique to the particular callsite.
@@ -152,7 +166,7 @@ fn make_mir_scope<'ll, 'tcx>(
         // We generate DILocations here based on the callsite's location in the
         // source code. A single location in the source code usually can't
         // produce multiple distinct calls so this mostly works, until
-        // proc-macros get involved. A proc-macro can generate multiple calls
+        // macros get involved. A macro can generate multiple calls
         // at the same span, which breaks the assumption that we're going to
         // produce a unique DILocation for every scope we process here. We
         // have to explicitly add discriminators if we see inlines into the
@@ -161,24 +175,29 @@ fn make_mir_scope<'ll, 'tcx>(
         // Note further that we can't key this hashtable on the span itself,
         // because these spans could have distinct SyntaxContexts. We have
         // to key on exactly what we're giving to LLVM.
-        match discriminators.entry(callsite_span.lo()) {
+        let inlined_at = match discriminators.entry(callsite_span.lo()) {
             Entry::Occupied(mut o) => {
                 *o.get_mut() += 1;
                 unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
-                    .expect("Failed to encode discriminator in DILocation")
             }
             Entry::Vacant(v) => {
                 v.insert(0);
-                loc
+                Some(loc)
+            }
+        };
+        match inlined_at {
+            Some(inlined_at) => {
+                debug_scope.as_mut().unwrap().inlined_at = Some(inlined_at);
+            }
+            None => {
+                // LLVM has a maximum discriminator that it can encode (currently
+                // it uses 12 bits for 4096 possible values). If we exceed that
+                // there is little we can do but drop the debug info.
+                debug_scope = None;
             }
         }
-    });
+    }
 
-    debug_context.scopes[scope] = DebugScope {
-        dbg_scope,
-        inlined_at: inlined_at.or(parent_scope.inlined_at),
-        file_start_pos: loc.file.start_pos,
-        file_end_pos: loc.file.end_position(),
-    };
+    debug_context.scopes[scope] = debug_scope;
     instantiated.insert(scope);
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 151923a3bd2..ef16e5bb459 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -11,10 +11,9 @@ use rustc_codegen_ssa::traits::*;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{
-    self, AdtKind, CoroutineArgsExt, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt,
-    Visibility,
+    self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
 };
 use rustc_session::config::{self, DebugInfo, Lto};
 use rustc_span::symbol::Symbol;
@@ -301,9 +300,8 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
         .insert(unique_type_id, recursion_marker_type_di_node(cx));
 
     let fn_ty = unique_type_id.expect_ty();
-    let signature = cx
-        .tcx
-        .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), fn_ty.fn_sig(cx.tcx));
+    let signature =
+        cx.tcx.normalize_erasing_late_bound_regions(cx.typing_env(), fn_ty.fn_sig(cx.tcx));
 
     let signature_di_nodes: SmallVec<_> = iter::once(
         // return type
@@ -1109,9 +1107,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
         }
     };
 
-    assert!(
-        up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
-    );
+    assert!(up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(cx.typing_env(), t)));
 
     let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
     let layout = cx.layout_of(closure_or_coroutine_ty);
@@ -1272,8 +1268,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
             let template_params: SmallVec<_> = iter::zip(args, names)
                 .filter_map(|(kind, name)| {
                     kind.as_type().map(|ty| {
-                        let actual_type =
-                            cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+                        let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
                         let actual_type_di_node = type_di_node(cx, actual_type);
                         let name = name.as_str();
                         unsafe {
@@ -1341,7 +1336,7 @@ pub(crate) fn build_global_var_di_node<'ll>(
     if nested {
         return;
     }
-    let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
+    let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, cx.typing_env());
     let type_di_node = type_di_node(cx, variable_type);
     let var_name = tcx.item_name(def_id);
     let var_name = var_name.as_str();
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 5120b63d173..4e461476040 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
 use rustc_middle::bug;
-use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, PolyExistentialTraitRef, Ty, TyCtxt};
 
 use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
 use crate::common::{AsCCharPtr, CodegenCx};
@@ -49,12 +49,15 @@ pub(super) enum UniqueTypeId<'tcx> {
 
 impl<'tcx> UniqueTypeId<'tcx> {
     pub(crate) fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self {
-        assert_eq!(t, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t));
+        assert_eq!(t, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), t));
         UniqueTypeId::Ty(t, private::HiddenZst)
     }
 
     pub(crate) fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self {
-        assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        assert_eq!(
+            enum_ty,
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
+        );
         UniqueTypeId::VariantPart(enum_ty, private::HiddenZst)
     }
 
@@ -63,7 +66,10 @@ impl<'tcx> UniqueTypeId<'tcx> {
         enum_ty: Ty<'tcx>,
         variant_idx: VariantIdx,
     ) -> Self {
-        assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        assert_eq!(
+            enum_ty,
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
+        );
         UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst)
     }
 
@@ -72,7 +78,10 @@ impl<'tcx> UniqueTypeId<'tcx> {
         enum_ty: Ty<'tcx>,
         variant_idx: VariantIdx,
     ) -> Self {
-        assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        assert_eq!(
+            enum_ty,
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
+        );
         UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst)
     }
 
@@ -81,10 +90,13 @@ impl<'tcx> UniqueTypeId<'tcx> {
         self_type: Ty<'tcx>,
         implemented_trait: Option<PolyExistentialTraitRef<'tcx>>,
     ) -> Self {
-        assert_eq!(self_type, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), self_type));
+        assert_eq!(
+            self_type,
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), self_type)
+        );
         assert_eq!(
             implemented_trait,
-            tcx.normalize_erasing_regions(ParamEnv::reveal_all(), implemented_trait)
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), implemented_trait)
         );
         UniqueTypeId::VTableTy(self_type, implemented_trait, private::HiddenZst)
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 89492e4b9fe..a8fdfbed592 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -15,8 +15,8 @@ use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, GenericArgsRef, Instance, ParamEnv, Ty, TypeVisitableExt};
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
+use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::Symbol;
@@ -294,12 +294,12 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
 
         // Initialize fn debug context (including scopes).
-        let empty_scope = DebugScope {
+        let empty_scope = Some(DebugScope {
             dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
             inlined_at: None,
             file_start_pos: BytePos(0),
             file_end_pos: BytePos(0),
-        };
+        });
         let mut fn_debug_context = FunctionDebugContext {
             scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
             inlined_function_scopes: Default::default(),
@@ -344,7 +344,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
         type_names::push_generic_params(
             tcx,
-            tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
+            tcx.normalize_erasing_regions(self.typing_env(), args),
             &mut name,
         );
 
@@ -481,8 +481,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 iter::zip(args, names)
                     .filter_map(|(kind, name)| {
                         kind.as_type().map(|ty| {
-                            let actual_type =
-                                cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+                            let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
                             let actual_type_metadata = type_di_node(cx, actual_type);
                             let name = name.as_str();
                             unsafe {
@@ -526,7 +525,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
                     let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
                         instance.args,
-                        ty::ParamEnv::reveal_all(),
+                        cx.typing_env(),
                         cx.tcx.type_of(impl_def_id),
                     );
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 960487ada16..6e841293477 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -1,7 +1,7 @@
 // Utility Functions.
 
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty};
 use tracing::trace;
 
@@ -62,7 +62,7 @@ pub(crate) fn wide_pointer_kind<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     pointee_ty: Ty<'tcx>,
 ) -> Option<WidePtrKind> {
-    let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
+    let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.typing_env());
     let layout = cx.layout_of(pointee_tail_ty);
     trace!(
         "wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e9c687d75e3..da7f94e8cf7 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -10,7 +10,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_hir as hir;
 use rustc_middle::mir::BinOp;
-use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, GenericArgsRef, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, Symbol, sym};
@@ -163,14 +163,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         span: Span,
     ) -> Result<(), ty::Instance<'tcx>> {
         let tcx = self.tcx;
-        let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+        let callee_ty = instance.ty(tcx, self.typing_env());
 
         let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else {
             bug!("expected fn item type, found {}", callee_ty);
         };
 
         let sig = callee_ty.fn_sig(tcx);
-        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = tcx.item_name(def_id);
@@ -192,7 +192,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     Some(instance),
                 )
             }
-            sym::likely => self.expect(args[0].immediate(), true),
             sym::is_val_statically_known => {
                 let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx);
                 let kind = self.type_kind(intrinsic_type);
@@ -213,7 +212,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     self.const_bool(false)
                 }
             }
-            sym::unlikely => self.expect(args[0].immediate(), false),
             sym::select_unpredictable => {
                 let cond = args[0].immediate();
                 assert_eq!(args[1].layout, args[2].layout);
@@ -1154,8 +1152,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     }
 
     let tcx = bx.tcx();
-    let sig =
-        tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
+    let sig = tcx.normalize_erasing_late_bound_regions(bx.typing_env(), callee_ty.fn_sig(tcx));
     let arg_tys = sig.inputs();
 
     // Sanity-check: all vector arguments must be immediates.
@@ -2189,7 +2186,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         match in_elem.kind() {
             ty::RawPtr(p_ty, _) => {
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
-                    bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
+                    bx.tcx.normalize_erasing_regions(bx.typing_env(), ty)
                 });
                 require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
@@ -2204,7 +2201,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         match out_elem.kind() {
             ty::RawPtr(p_ty, _) => {
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
-                    bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
+                    bx.tcx.normalize_erasing_regions(bx.typing_env(), ty)
                 });
                 require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index ea8857b4739..33789c6261f 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -3,7 +3,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 use rustc_session::config::CrateType;
 use rustc_target::spec::RelocModel;
@@ -26,11 +26,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
         let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
         // Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure
         // out the llvm type from the actual evaluated initializer.
-        let ty = if nested {
-            self.tcx.types.unit
-        } else {
-            instance.ty(self.tcx, ty::ParamEnv::reveal_all())
-        };
+        let ty =
+            if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) };
         let llty = self.layout_of(ty).llvm_type(self);
 
         let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 4f3664a503d..6ee599c9964 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1279,7 +1279,7 @@ impl<'a> WasmLd<'a> {
         let mut wasm_ld = WasmLd { cmd, sess };
         if sess.target_features.contains(&sym::atomics) {
             wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
-            if sess.target.os == "unknown" {
+            if sess.target.os == "unknown" || sess.target.os == "none" {
                 wasm_ld.link_args(&[
                     "--export=__wasm_init_tls",
                     "--export=__tls_size",
@@ -1403,7 +1403,7 @@ impl<'a> Linker for WasmLd<'a> {
         // symbols explicitly passed via the `--export` flags above and hides all
         // others. Various bits and pieces of wasm32-unknown-unknown tooling use
         // this, so be sure these symbols make their way out of the linker as well.
-        if self.sess.target.os == "unknown" {
+        if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
             self.link_args(&["--export=__heap_base", "--export=__data_end"]);
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 850d36872dd..d9152c5d080 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -595,8 +595,10 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
 
     let (conv, args) = instance
         .map(|i| {
-            tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty())))
-                .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed"))
+            tcx.fn_abi_of_instance(
+                ty::TypingEnv::fully_monomorphized().as_query_input((i, ty::List::empty())),
+            )
+            .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed"))
         })
         .map(|fnabi| (fnabi.conv, &fnabi.args[..]))
         .unwrap_or((Conv::Rust, &[]));
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index ef95ab94062..27c9cb0b31e 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -21,8 +21,8 @@ use rustc_middle::middle::{exported_symbols, lang_items};
 use rustc_middle::mir::BinOp;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::query::Providers;
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_span::symbol::sym;
@@ -119,7 +119,8 @@ pub fn validate_trivial_unsize<'tcx>(
 ) -> bool {
     match (source_data.principal(), target_data.principal()) {
         (Some(hr_source_principal), Some(hr_target_principal)) => {
-            let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
+            let (infcx, param_env) =
+                tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
             let universe = infcx.universe();
             let ocx = ObligationCtxt::new(&infcx);
             infcx.enter_forall(hr_target_principal, |target_principal| {
@@ -130,7 +131,7 @@ pub fn validate_trivial_unsize<'tcx>(
                 );
                 let Ok(()) = ocx.eq_trace(
                     &ObligationCause::dummy(),
-                    ty::ParamEnv::reveal_all(),
+                    param_env,
                     ToTrace::to_trace(
                         &ObligationCause::dummy(),
                         hr_target_principal,
@@ -165,7 +166,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ) -> Bx::Value {
     let cx = bx.cx();
     let (source, target) =
-        cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.param_env());
+        cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.typing_env());
     match (source.kind(), target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize(
             len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"),
@@ -466,10 +467,9 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         // late-bound regions, since late-bound
         // regions must appear in the argument
         // listing.
-        let main_ret_ty = cx.tcx().normalize_erasing_regions(
-            ty::ParamEnv::reveal_all(),
-            main_ret_ty.no_bound_vars().unwrap(),
-        );
+        let main_ret_ty = cx
+            .tcx()
+            .normalize_erasing_regions(cx.typing_env(), main_ret_ty.no_bound_vars().unwrap());
 
         let Some(llfn) = cx.declare_c_main(llfty) else {
             // FIXME: We should be smart and show a better diagnostic here.
@@ -495,7 +495,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
             let start_instance = ty::Instance::expect_resolve(
                 cx.tcx(),
-                ty::ParamEnv::reveal_all(),
+                cx.typing_env(),
                 start_def_id,
                 cx.tcx().mk_args(&[main_ret_ty.into()]),
                 DUMMY_SP,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 27bc58516c0..6c4f6d37972 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -21,9 +21,7 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
 use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Mutability};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
-use rustc_middle::ty::{
-    self, ExistentialProjection, GenericArgKind, GenericArgsRef, ParamEnv, Ty, TyCtxt,
-};
+use rustc_middle::ty::{self, ExistentialProjection, GenericArgKind, GenericArgsRef, Ty, TyCtxt};
 use smallvec::SmallVec;
 
 use crate::debuginfo::wants_c_like_enum_debuginfo;
@@ -82,7 +80,7 @@ fn push_debuginfo_type_name<'tcx>(
         ty::Adt(def, args) => {
             // `layout_for_cpp_like_fallback` will be `Some` if we want to use the fallback encoding.
             let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
-                match tcx.layout_of(ParamEnv::reveal_all().and(t)) {
+                match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)) {
                     Ok(layout) => {
                         if !wants_c_like_enum_debuginfo(tcx, layout) {
                             Some(layout)
@@ -248,8 +246,10 @@ fn push_debuginfo_type_name<'tcx>(
             };
 
             if let Some(principal) = trait_data.principal() {
-                let principal =
-                    tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
+                let principal = tcx.normalize_erasing_late_bound_regions(
+                    ty::TypingEnv::fully_monomorphized(),
+                    principal,
+                );
                 push_item_name(tcx, principal.def_id, qualified, output);
                 let principal_has_generic_params =
                     push_generic_params_internal(tcx, principal.args, output, visited);
@@ -350,8 +350,10 @@ fn push_debuginfo_type_name<'tcx>(
                 return;
             }
 
-            let sig =
-                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
+            let sig = tcx.normalize_erasing_late_bound_regions(
+                ty::TypingEnv::fully_monomorphized(),
+                t.fn_sig(tcx),
+            );
 
             if cpp_like_debuginfo {
                 // Format as a C++ function pointer: return_type (*)(params...)
@@ -415,7 +417,8 @@ fn push_debuginfo_type_name<'tcx>(
             // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of
             // an artificial `enum2$<>` type, as defined in msvc_enum_fallback().
             if cpp_like_debuginfo && t.is_coroutine() {
-                let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
+                let ty_and_layout =
+                    tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(t)).unwrap();
                 msvc_enum_fallback(
                     tcx,
                     ty_and_layout,
@@ -529,8 +532,8 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     }
 
     if let Some(trait_ref) = trait_ref {
-        let trait_ref =
-            tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
+        let trait_ref = tcx
+            .normalize_erasing_late_bound_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
         push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
         visited.clear();
         push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
@@ -639,7 +642,7 @@ fn push_generic_params_internal<'tcx>(
     output: &mut String,
     visited: &mut FxHashSet<Ty<'tcx>>,
 ) -> bool {
-    assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args));
+    assert_eq!(args, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args));
     let mut args = args.non_erasable_generics().peekable();
     if args.peek().is_none() {
         return false;
@@ -678,14 +681,14 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                     // FIXME: directly extract the bits from a valtree instead of evaluating an
                     // already evaluated `Const` in order to get the bits.
                     let bits = ct
-                        .try_to_bits(tcx, ty::ParamEnv::reveal_all())
+                        .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in codegen");
                     let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
                     write!(output, "{val}")
                 }
                 ty::Uint(_) => {
                     let val = ct
-                        .try_to_bits(tcx, ty::ParamEnv::reveal_all())
+                        .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in codegen");
                     write!(output, "{val}")
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 027d80350e4..e3ed12b5ce6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -377,20 +377,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // If there are two targets (one conditional, one fallback), emit `br` instead of
             // `switch`.
             let (test_value, target) = target_iter.next().unwrap();
-            let lltrue = helper.llbb_with_cleanup(self, target);
-            let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
+            let otherwise = targets.otherwise();
+            let lltarget = helper.llbb_with_cleanup(self, target);
+            let llotherwise = helper.llbb_with_cleanup(self, otherwise);
+            let target_cold = self.cold_blocks[target];
+            let otherwise_cold = self.cold_blocks[otherwise];
+            // If `target_cold == otherwise_cold`, the branches have the same weight
+            // so there is no expectation. If they differ, the `target` branch is expected
+            // when the `otherwise` branch is cold.
+            let expect = if target_cold == otherwise_cold { None } else { Some(otherwise_cold) };
             if switch_ty == bx.tcx().types.bool {
                 // Don't generate trivial icmps when switching on bool.
                 match test_value {
-                    0 => bx.cond_br(discr_value, llfalse, lltrue),
-                    1 => bx.cond_br(discr_value, lltrue, llfalse),
+                    0 => {
+                        let expect = expect.map(|e| !e);
+                        bx.cond_br_with_expect(discr_value, llotherwise, lltarget, expect);
+                    }
+                    1 => {
+                        bx.cond_br_with_expect(discr_value, lltarget, llotherwise, expect);
+                    }
                     _ => bug!(),
                 }
             } else {
                 let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
                 let llval = bx.const_uint_big(switch_llty, test_value);
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
-                bx.cond_br(cmp, lltrue, llfalse);
+                bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect);
             }
         } else if self.cx.sess().opts.optimize == OptLevel::No
             && target_iter.len() == 2
@@ -765,7 +777,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             let do_panic = !bx
                 .tcx()
-                .check_validity_requirement((requirement, bx.param_env().and(ty)))
+                .check_validity_requirement((requirement, bx.typing_env().as_query_input(ty)))
                 .expect("expect to have layout during codegen");
 
             let layout = bx.layout_of(ty);
@@ -836,14 +848,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let (instance, mut llfn) = match *callee.layout.ty.kind() {
             ty::FnDef(def_id, args) => (
                 Some(
-                    ty::Instance::expect_resolve(
-                        bx.tcx(),
-                        ty::ParamEnv::reveal_all(),
-                        def_id,
-                        args,
-                        fn_span,
-                    )
-                    .polymorphize(bx.tcx()),
+                    ty::Instance::expect_resolve(bx.tcx(), bx.typing_env(), def_id, args, fn_span)
+                        .polymorphize(bx.tcx()),
                 ),
                 None,
             ),
@@ -1179,7 +1185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     if let ty::FnDef(def_id, args) = *const_.ty().kind() {
                         let instance = ty::Instance::resolve_for_fn_ptr(
                             bx.tcx(),
-                            ty::ParamEnv::reveal_all(),
+                            bx.typing_env(),
                             def_id,
                             args,
                         )
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 54b9c9cc89f..7676e1e171a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -1,6 +1,6 @@
 use rustc_abi::BackendRepr;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, mir, span_bug};
 
@@ -24,7 +24,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // `MirUsedCollector` visited all required_consts before codegen began, so if we got here
         // there can be no more constants that fail to evaluate.
         self.monomorphize(constant.const_)
-            .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), constant.span)
+            .eval(self.cx.tcx(), self.cx.typing_env(), constant.span)
             .expect("erroneous constant missed by mono item collection")
     }
 
@@ -57,7 +57,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             other => span_bug!(constant.span, "{other:#?}"),
         };
         let uv = self.monomorphize(uv);
-        self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span)
+        self.cx.tcx().const_eval_resolve_for_typeck(self.cx.typing_env(), uv, constant.span)
     }
 
     /// process constant containing SIMD shuffle indices & constant vectors
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 21d20475408..d4d7f16db55 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -20,7 +20,9 @@ use crate::traits::*;
 
 pub struct FunctionDebugContext<'tcx, S, L> {
     /// Maps from source code to the corresponding debug info scope.
-    pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
+    /// May be None if the backend is not capable of representing the scope for
+    /// some reason.
+    pub scopes: IndexVec<mir::SourceScope, Option<DebugScope<S, L>>>,
 
     /// Maps from an inlined function to its debug info declaration.
     pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
@@ -231,7 +233,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &self,
         source_info: mir::SourceInfo,
     ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
-        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
+        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]?;
         let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span);
         Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span))
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index c9e38bb80c2..299b98c0a4f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -59,14 +59,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         llresult: Bx::Value,
         span: Span,
     ) -> Result<(), ty::Instance<'tcx>> {
-        let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all());
+        let callee_ty = instance.ty(bx.tcx(), bx.typing_env());
 
         let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else {
             bug!("expected fn item type, found {}", callee_ty);
         };
 
         let sig = callee_ty.fn_sig(bx.tcx());
-        let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig = bx.tcx().normalize_erasing_late_bound_regions(bx.typing_env(), sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = bx.tcx().item_name(def_id);
@@ -146,10 +146,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             | sym::type_id
             | sym::type_name
             | sym::variant_count => {
-                let value = bx
-                    .tcx()
-                    .const_eval_instance(ty::ParamEnv::reveal_all(), instance, span)
-                    .unwrap();
+                let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap();
                 OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
             }
             sym::arith_offset => {
@@ -498,6 +495,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
+            sym::cold_path => {
+                // This is a no-op. The intrinsic is just a hint to the optimizer.
+                return Ok(());
+            }
+
             _ => {
                 // Need to use backend-specific things in the implementation.
                 return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 20fd08923ec..0cbc5c45736 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -4,7 +4,7 @@ use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::{UnwindTerminateReason, traversal};
-use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_target::callconv::{FnAbi, PassMode};
@@ -91,6 +91,10 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     /// Cached terminate upon unwinding block and its reason
     terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>,
 
+    /// A bool flag for each basic block indicating whether it is a cold block.
+    /// A cold block is a block that is unlikely to be executed at runtime.
+    cold_blocks: IndexVec<mir::BasicBlock, bool>,
+
     /// The location where each MIR arg/var/tmp/ret is stored. This is
     /// usually an `PlaceRef` representing an alloca, but not always:
     /// sometimes we can skip the alloca and just store the value
@@ -124,7 +128,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         debug!("monomorphize: self.instance={:?}", self.instance);
         self.instance.instantiate_mir_and_normalize_erasing_regions(
             self.cx.tcx(),
-            ty::ParamEnv::reveal_all(),
+            self.cx.typing_env(),
             ty::EarlyBinder::bind(value),
         )
     }
@@ -207,6 +211,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         cleanup_kinds,
         landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
         funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
+        cold_blocks: find_cold_blocks(cx.tcx(), mir),
         locals: locals::Locals::empty(),
         debug_context,
         per_local_var_debug_info: None,
@@ -477,3 +482,39 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     args
 }
+
+fn find_cold_blocks<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mir: &mir::Body<'tcx>,
+) -> IndexVec<mir::BasicBlock, bool> {
+    let local_decls = &mir.local_decls;
+
+    let mut cold_blocks: IndexVec<mir::BasicBlock, bool> =
+        IndexVec::from_elem(false, &mir.basic_blocks);
+
+    // Traverse all basic blocks from end of the function to the start.
+    for (bb, bb_data) in traversal::postorder(mir) {
+        let terminator = bb_data.terminator();
+
+        // If a BB ends with a call to a cold function, mark it as cold.
+        if let mir::TerminatorKind::Call { ref func, .. } = terminator.kind
+            && let ty::FnDef(def_id, ..) = *func.ty(local_decls, tcx).kind()
+            && let attrs = tcx.codegen_fn_attrs(def_id)
+            && attrs.flags.contains(CodegenFnAttrFlags::COLD)
+        {
+            cold_blocks[bb] = true;
+            continue;
+        }
+
+        // If all successors of a BB are cold and there's at least one of them, mark this BB as cold
+        let mut succ = terminator.successors();
+        if let Some(first) = succ.next()
+            && cold_blocks[first]
+            && succ.all(|s| cold_blocks[s])
+        {
+            cold_blocks[bb] = true;
+        }
+    }
+
+    cold_blocks
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 0e1cd662f91..f63b2d139c5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -474,7 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             ty::FnDef(def_id, args) => {
                                 let instance = ty::Instance::resolve_for_fn_ptr(
                                     bx.tcx(),
-                                    ty::ParamEnv::reveal_all(),
+                                    bx.typing_env(),
                                     def_id,
                                     args,
                                 )
@@ -709,7 +709,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     mir::NullOp::OffsetOf(fields) => {
                         let val = bx
                             .tcx()
-                            .offset_of_subfield(bx.param_env(), layout, fields.iter())
+                            .offset_of_subfield(bx.typing_env(), layout, fields.iter())
                             .bytes();
                         bx.cx().const_usize(val)
                     }
@@ -727,7 +727,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(bx.cx().tcx().is_static(def_id));
-                let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
+                let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id, bx.typing_env()));
                 let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id)
                 {
                     let instance = ty::Instance {
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 1681ea1de5f..cd55a838a75 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -92,6 +92,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::ConstEvalCounter
             | mir::StatementKind::PlaceMention(..)
+            | mir::StatementKind::BackwardIncompatibleDropHint { .. }
             | mir::StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 74cd522a30f..b0138ac8bfe 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -84,6 +84,26 @@ pub trait BuilderMethods<'a, 'tcx>:
         then_llbb: Self::BasicBlock,
         else_llbb: Self::BasicBlock,
     );
+
+    // Conditional with expectation.
+    //
+    // This function is opt-in for back ends.
+    //
+    // The default implementation calls `self.expect()` before emiting the branch
+    // by calling `self.cond_br()`
+    fn cond_br_with_expect(
+        &mut self,
+        mut cond: Self::Value,
+        then_llbb: Self::BasicBlock,
+        else_llbb: Self::BasicBlock,
+        expect: Option<bool>,
+    ) {
+        if let Some(expect) = expect {
+            cond = self.expect(cond, expect);
+        }
+        self.cond_br(cond, then_llbb, else_llbb)
+    }
+
     fn switch(
         &mut self,
         v: Self::Value,
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 44ba2262149..6292d321f6b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{AddressSpace, Float, Integer};
 use rustc_middle::bug;
-use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
 use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, Reg};
 
@@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes {
 }
 
 pub trait DerivedTypeCodegenMethods<'tcx>:
-    BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx>
+    BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
 {
     fn type_int(&self) -> Self::Type {
         match &self.sess().target.c_int_width[..] {
@@ -74,24 +74,23 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
     }
 
     fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all())
+        ty.needs_drop(self.tcx(), self.typing_env())
     }
 
     fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all())
+        ty.is_sized(self.tcx(), self.typing_env())
     }
 
     fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all())
+        ty.is_freeze(self.tcx(), self.typing_env())
     }
 
     fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
-        let param_env = ty::ParamEnv::reveal_all();
-        if ty.is_sized(self.tcx(), param_env) {
+        if ty.is_sized(self.tcx(), self.typing_env()) {
             return false;
         }
 
-        let tail = self.tcx().struct_tail_for_codegen(ty, param_env);
+        let tail = self.tcx().struct_tail_for_codegen(ty, self.typing_env());
         match tail.kind() {
             ty::Foreign(..) => false,
             ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
@@ -101,7 +100,10 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
 }
 
 impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where
-    Self: BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx>
+    Self: BaseTypeCodegenMethods<'tcx>
+        + MiscCodegenMethods<'tcx>
+        + HasTyCtxt<'tcx>
+        + HasTypingEnv<'tcx>
 {
 }
 
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 15027ae0c18..f93f4d36e45 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -403,7 +403,7 @@ const_eval_uninhabited_enum_variant_written =
 const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
     .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
 const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
-    .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
+    .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
 
 const_eval_unreachable = entering unreachable code
 const_eval_unreachable_unwind =
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index c3efca28c68..1129b5caec5 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -272,9 +272,18 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
     /// context.
     pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
         let gate = match op.status_in_item(self.ccx) {
-            Status::Unstable { gate, safe_to_expose_on_stable, is_function_call }
-                if self.tcx.features().enabled(gate) =>
-            {
+            Status::Unstable {
+                gate,
+                safe_to_expose_on_stable,
+                is_function_call,
+                gate_already_checked,
+            } if gate_already_checked || self.tcx.features().enabled(gate) => {
+                if gate_already_checked {
+                    assert!(
+                        !safe_to_expose_on_stable,
+                        "setting `gate_already_checked` without `safe_to_expose_on_stable` makes no sense"
+                    );
+                }
                 // Generally this is allowed since the feature gate is enabled -- except
                 // if this function wants to be safe-to-expose-on-stable.
                 if !safe_to_expose_on_stable
@@ -379,7 +388,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             return false;
         }
 
-        let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
+        let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(self.body.typing_env(tcx));
         let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
         let body_id = self.body.source.def_id().expect_local();
@@ -389,11 +398,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 ty::BoundConstness::Const
             }
         };
-        let const_conditions = ocx.normalize(
-            &ObligationCause::misc(call_span, body_id),
-            self.param_env,
-            const_conditions,
-        );
+        let const_conditions =
+            ocx.normalize(&ObligationCause::misc(call_span, body_id), param_env, const_conditions);
         ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| {
             Obligation::new(
                 tcx,
@@ -402,7 +408,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                     body_id,
                     ObligationCauseCode::WhereClause(callee, span),
                 ),
-                self.param_env,
+                param_env,
                 trait_ref.to_host_effect_clause(tcx, host_polarity),
             )
         }));
@@ -603,6 +609,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
     }
@@ -745,13 +752,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             self.check_op(ops::IntrinsicUnstable {
                                 name: intrinsic.name,
                                 feature,
-                                const_stable: is_const_stable,
+                                const_stable_indirect: is_const_stable,
                             });
                         }
                         Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
                             // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it
                             // can be *directly* invoked from stable const code) does not always
-                            // have the `#[rustc_const_stable_intrinsic]` attribute (which controls
+                            // have the `#[rustc_intrinsic_const_stable_indirect]` attribute (which controls
                             // exposing an intrinsic indirectly); we accept this call anyway.
                         }
                     }
@@ -800,6 +807,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                         // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
                         // the callee is safe to expose, to avoid bypassing recursive stability.
+                        // This is not ideal since it means the user sees an error, not the macro
+                        // author, but that's also the case if one forgets to set
+                        // `#[allow_internal_unstable]` in the first place. Note that this cannot be
+                        // integrated in the check below since we want to enforce
+                        // `callee_safe_to_expose_on_stable` even if
+                        // `!self.enforce_recursive_const_stability()`.
                         if (self.span.allows_unstable(feature)
                             || implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
                             && callee_safe_to_expose_on_stable
@@ -830,15 +843,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                     && issue == NonZero::new(27812)
                                     && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
                             };
-                        // We do *not* honor this if we are in the "danger zone": we have to enforce
-                        // recursive const-stability and the callee is not safe-to-expose. In that
-                        // case we need `check_op` to do the check.
-                        let danger_zone = !callee_safe_to_expose_on_stable
-                            && self.enforce_recursive_const_stability();
-                        if danger_zone || !feature_enabled {
+                        // Even if the feature is enabled, we still need check_op to double-check
+                        // this if the callee is not safe to expose on stable.
+                        if !feature_enabled || !callee_safe_to_expose_on_stable {
                             self.check_op(ops::FnCallUnstable {
                                 def_id: callee,
                                 feature,
+                                feature_enabled,
                                 safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
                             });
                         }
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index ebdd55a4f70..80d3c6448aa 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -24,17 +24,15 @@ mod resolver;
 pub struct ConstCx<'mir, 'tcx> {
     pub body: &'mir mir::Body<'tcx>,
     pub tcx: TyCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
+    pub typing_env: ty::TypingEnv<'tcx>,
     pub const_kind: Option<hir::ConstContext>,
 }
 
 impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
-        let def_id = body.source.def_id().expect_local();
-        let param_env = tcx.param_env(def_id);
-
+        let typing_env = body.typing_env(tcx);
         let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
-        ConstCx { body, tcx, param_env, const_kind }
+        ConstCx { body, tcx, typing_env, const_kind }
     }
 
     pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> {
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 036ca763280..8ba6b89aad4 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -28,6 +28,9 @@ pub enum Status {
     Unstable {
         /// The feature that must be enabled to use this operation.
         gate: Symbol,
+        /// Whether the feature gate was already checked (because the logic is a bit more
+        /// complicated than just checking a single gate).
+        gate_already_checked: bool,
         /// Whether it is allowed to use this operation from stable `const fn`.
         /// This will usually be `false`.
         safe_to_expose_on_stable: bool,
@@ -82,6 +85,7 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
         // We use the `const_trait_impl` gate for all conditionally-const calls.
         Status::Unstable {
             gate: sym::const_trait_impl,
+            gate_already_checked: false,
             safe_to_expose_on_stable: false,
             // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
             is_function_call: false,
@@ -116,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
     #[allow(rustc::untranslatable_diagnostic)]
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
         let FnCallNonConst { callee, args, span, call_source } = *self;
-        let ConstCx { tcx, param_env, .. } = *ccx;
+        let ConstCx { tcx, typing_env, .. } = *ccx;
         let caller = ccx.def_id();
 
         let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
@@ -142,13 +146,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     }
                 }
                 ty::Adt(..) => {
+                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
                     let obligation =
                         Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
-
-                    let infcx = tcx.infer_ctxt().build(ccx.body.typing_mode(tcx));
                     let mut selcx = SelectionContext::new(&infcx);
                     let implsrc = selcx.select(&obligation);
-
                     if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
                         // FIXME(const_trait_impl) revisit this
                         if !tcx.is_const_trait_impl(data.impl_def_id) {
@@ -162,7 +164,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
         };
 
         let call_kind =
-            call_kind(tcx, ccx.param_env, callee, args, span, call_source.from_hir_call(), None);
+            call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None);
 
         debug!(?call_kind);
 
@@ -330,6 +332,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
 pub(crate) struct FnCallUnstable {
     pub def_id: DefId,
     pub feature: Symbol,
+    /// If this is true, then the feature is enabled, but we need to still check if it is safe to
+    /// expose on stable.
+    pub feature_enabled: bool,
     pub safe_to_expose_on_stable: bool,
 }
 
@@ -337,12 +342,14 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable {
             gate: self.feature,
+            gate_already_checked: self.feature_enabled,
             safe_to_expose_on_stable: self.safe_to_expose_on_stable,
             is_function_call: true,
         }
     }
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
+        assert!(!self.feature_enabled);
         let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
             span,
             def_path: ccx.tcx.def_path_str(self.def_id),
@@ -376,14 +383,15 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
 pub(crate) struct IntrinsicUnstable {
     pub name: Symbol,
     pub feature: Symbol,
-    pub const_stable: bool,
+    pub const_stable_indirect: bool,
 }
 
 impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable {
             gate: self.feature,
-            safe_to_expose_on_stable: self.const_stable,
+            gate_already_checked: false,
+            safe_to_expose_on_stable: self.const_stable_indirect,
             // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
             // that's not a trivial change!
             is_function_call: false,
@@ -410,6 +418,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
         {
             Status::Unstable {
                 gate: sym::const_async_blocks,
+                gate_already_checked: false,
                 safe_to_expose_on_stable: false,
                 is_function_call: false,
             }
diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
index 0173a528c22..f6eb130fbd3 100644
--- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
@@ -32,17 +32,15 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
 /// This is separate from the rest of the const checking logic because it must run after drop
 /// elaboration.
 pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
-    let def_id = body.source.def_id().expect_local();
-    let const_kind = tcx.hir().body_const_context(def_id);
-    if const_kind.is_none() {
+    let ccx = ConstCx::new(tcx, body);
+    if ccx.const_kind.is_none() {
         return;
     }
 
-    if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
+    if tcx.has_attr(body.source.def_id(), sym::rustc_do_not_const_check) {
         return;
     }
 
-    let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) };
     if !checking_enabled(&ccx) {
         return;
     }
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 29a08579175..bc416acc58d 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -106,20 +106,24 @@ impl Qualif for HasMutInterior {
         // Instead we invoke an obligation context manually, and provide the opaque type inference settings
         // that allow the trait solver to just error out instead of cycling.
         let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span));
-
+        // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR
+        // typeck results without causing query cycles, we should use this here instead of defining
+        // opaque types.
+        let typing_env = ty::TypingEnv {
+            typing_mode: ty::TypingMode::analysis_in_body(
+                cx.tcx,
+                cx.body.source.def_id().expect_local(),
+            ),
+            param_env: cx.typing_env.param_env,
+        };
+        let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(typing_env);
+        let ocx = ObligationCtxt::new(&infcx);
         let obligation = Obligation::new(
             cx.tcx,
             ObligationCause::dummy_with_span(cx.body.span),
-            cx.param_env,
+            param_env,
             ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
         );
-
-        // FIXME(#132279): This should eventually use the already defined hidden types.
-        let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body(
-            cx.tcx,
-            cx.body.source.def_id().expect_local(),
-        ));
-        let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(obligation);
         let errors = ocx.select_all_or_error();
         !errors.is_empty()
@@ -156,7 +160,7 @@ impl Qualif for NeedsDrop {
     }
 
     fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(cx.tcx, cx.param_env)
+        ty.needs_drop(cx.tcx, cx.typing_env)
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 74eb6b37fbb..0f9a460ca1b 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -120,7 +120,7 @@ where
     ///
     /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
     fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
-        !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env)
+        !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.typing_env)
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 6686413bf02..1271d9d2d0d 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -152,13 +152,20 @@ where
             let span = span.substitute_dummy(our_span);
             let err = mk(span, frames);
             let mut err = tcx.dcx().create_err(err);
+            let can_be_spurious = matches!(error, InterpErrorKind::ResourceExhaustion(_));
 
             let msg = error.diagnostic_message();
             error.add_args(&mut err);
 
             // Use *our* span to label the interp error
             err.span_label(our_span, msg);
-            ErrorHandled::Reported(err.emit().into(), span)
+            let g = err.emit();
+            let reported = if can_be_spurious {
+                ReportedErrorInfo::spurious(g)
+            } else {
+                ReportedErrorInfo::from(g)
+            };
+            ErrorHandled::Reported(reported, span)
         }
     }
 }
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 a430d9dc797..647d880e2bf 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -7,8 +7,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
 use rustc_middle::mir::{self, ConstAlloc, ConstValue};
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::traits::Reveal;
-use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
@@ -31,7 +30,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
     cid: GlobalId<'tcx>,
     body: &'tcx mir::Body<'tcx>,
 ) -> InterpResult<'tcx, R> {
-    trace!(?ecx.param_env);
     let tcx = *ecx.tcx;
     assert!(
         cid.promoted.is_some()
@@ -126,14 +124,14 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
 pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
     tcx: TyCtxt<'tcx>,
     root_span: Span,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     can_access_mut_global: CanAccessMutGlobal,
 ) -> CompileTimeInterpCx<'tcx> {
-    debug!("mk_eval_cx: {:?}", param_env);
+    debug!("mk_eval_cx: {:?}", typing_env);
     InterpCx::new(
         tcx,
         root_span,
-        param_env,
+        typing_env,
         CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No),
     )
 }
@@ -142,11 +140,11 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
 /// Returns both the context and an `OpTy` that represents the constant.
 pub fn mk_eval_cx_for_const_val<'tcx>(
     tcx: TyCtxtAt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     val: mir::ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
-    let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No);
+    let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No);
     // FIXME: is it a problem to discard the error here?
     let op = ecx.const_val_to_op(val, ty, None).discard_err()?;
     Some((ecx, op))
@@ -221,7 +219,7 @@ pub(super) fn op_to_const<'tcx>(
                 let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
                 debug_assert!(
                     matches!(
-                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.param_env).kind(),
+                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(),
                         ty::Str | ty::Slice(..),
                     ),
                     "`ConstValue::Slice` is for slice-tailed types only, but got {}",
@@ -245,7 +243,7 @@ pub(super) fn op_to_const<'tcx>(
 pub(crate) fn turn_into_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     constant: ConstAlloc<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
+    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
 ) -> ConstValue<'tcx> {
     let cid = key.value;
     let def_id = cid.instance.def.def_id();
@@ -254,7 +252,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
     let ecx = mk_eval_cx_to_read_const_val(
         tcx,
         tcx.def_span(key.value.instance.def_id()),
-        key.param_env,
+        key.typing_env,
         CanAccessMutGlobal::from(is_static),
     );
 
@@ -274,21 +272,16 @@ pub(crate) fn turn_into_const_value<'tcx>(
 #[instrument(skip(tcx), level = "debug")]
 pub fn eval_to_const_value_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
+    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
-    // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
-    // opaque types. This is needed for trivial things like `size_of`, but also for using associated
-    // types that are not specified in the opaque type.
-    assert_eq!(key.param_env.reveal(), Reveal::All);
-
     // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
     // Catch such calls and evaluate them instead of trying to load a constant's MIR.
     if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def {
-        let ty = key.value.instance.ty(tcx, key.param_env);
+        let ty = key.value.instance.ty(tcx, key.typing_env);
         let ty::FnDef(_, args) = ty.kind() else {
             bug!("intrinsic with type {:?}", ty);
         };
-        return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err(
+        return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err(
             |error| {
                 let span = tcx.def_span(def_id);
 
@@ -315,7 +308,7 @@ pub fn eval_static_initializer_provider<'tcx>(
 
     let instance = ty::Instance::mono(tcx, def_id.to_def_id());
     let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
-    eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all())
+    eval_in_interpreter(tcx, cid, ty::TypingEnv::fully_monomorphized())
 }
 
 pub trait InterpretationResult<'tcx> {
@@ -340,16 +333,14 @@ impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> {
 #[instrument(skip(tcx), level = "debug")]
 pub fn eval_to_allocation_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
+    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
     // This shouldn't be used for statics, since statics are conceptually places,
     // not values -- so what we do here could break pointer identity.
     assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
-    // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
-    // opaque types. This is needed for trivial things like `size_of`, but also for using associated
-    // types that are not specified in the opaque type.
-
-    assert_eq!(key.param_env.reveal(), Reveal::All);
+    // Const eval always happens in PostAnalysis mode . See the comment in
+    // `InterpCx::new` for more details.
+    debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
     if cfg!(debug_assertions) {
         // Make sure we format the instance even if we do not print it.
         // This serves as a regression test against an ICE on printing.
@@ -360,13 +351,13 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         trace!("const eval: {:?} ({})", key, instance);
     }
 
-    eval_in_interpreter(tcx, key.value, key.param_env)
+    eval_in_interpreter(tcx, key.value, key.typing_env)
 }
 
 fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
     tcx: TyCtxt<'tcx>,
     cid: GlobalId<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 ) -> Result<R, ErrorHandled> {
     let def = cid.instance.def.def_id();
     let is_static = tcx.is_static(def);
@@ -374,7 +365,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
     let mut ecx = InterpCx::new(
         tcx,
         tcx.def_span(def),
-        param_env,
+        typing_env,
         // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
         // they do not have to behave "as if" they were evaluated at runtime.
         // For consts however we want to ensure they behave "as if" they were evaluated at runtime,
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 62115aef4a7..b27e3606f38 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
 use rustc_middle::mir::AssertMessage;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Span;
@@ -249,9 +249,10 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
         } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
             // For panic_fmt, call const_panic_fmt instead.
             let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
+            // FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here.
             let new_instance = ty::Instance::expect_resolve(
                 *self.tcx,
-                ty::ParamEnv::reveal_all(),
+                ty::TypingEnv::fully_monomorphized(),
                 const_def_id,
                 instance.args,
                 self.cur_span(),
@@ -263,6 +264,12 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
     }
 
     /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
+    /// Returns `2` if the result is unknown.
+    /// Returns `1` if the pointers are guaranteed equal.
+    /// Returns `0` if the pointers are guaranteed inequal.
+    ///
+    /// Note that this intrinsic is exposed on stable for comparison with null. In other words, any
+    /// change to this function that affects comparison with null is insta-stable!
     fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
         interp_ok(match (a, b) {
             // Comparisons between integers are always known.
@@ -660,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                 .is_some_and(|p| !p.immutable())
         {
             // That next check is expensive, that's why we have all the guards above.
-            let is_immutable = ty.is_freeze(*ecx.tcx, ecx.param_env);
+            let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env());
             let place = ecx.ref_to_mplace(val)?;
             let new_place = if is_immutable {
                 place.map_provenance(CtfeProvenance::as_immutable)
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index d5012236c34..8cbdcd68e13 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -38,8 +38,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
     val: mir::ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<mir::DestructuredConstant<'tcx>> {
-    let param_env = ty::ParamEnv::reveal_all();
-    let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?;
+    let typing_env = ty::TypingEnv::fully_monomorphized();
+    let (ecx, op) = mk_eval_cx_for_const_val(tcx, typing_env, val, ty)?;
 
     // We go to `usize` as we cannot allocate anything bigger anyway.
     let (field_count, variant, down) = match ty.kind() {
@@ -76,10 +76,12 @@ pub fn tag_for_variant_provider<'tcx>(
 ) -> Option<ty::ScalarInt> {
     assert!(ty.is_enum());
 
+    // FIXME: This uses an empty `TypingEnv` even though
+    // it may be used by a generic CTFE.
     let ecx = InterpCx::new(
         tcx,
         ty.default_span(tcx),
-        ty::ParamEnv::reveal_all(),
+        ty::TypingEnv::fully_monomorphized(),
         crate::const_eval::DummyMachine,
     );
 
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index ea88b2ed22e..515028e6826 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -228,16 +228,19 @@ fn create_valtree_place<'tcx>(
 /// Evaluates a constant and turns it into a type-level constant value.
 pub(crate) fn eval_to_valtree<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     cid: GlobalId<'tcx>,
 ) -> EvalToValTreeResult<'tcx> {
-    let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
+    // Const eval always happens in PostAnalysis mode . See the comment in
+    // `InterpCx::new` for more details.
+    debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
+    let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
 
     // FIXME Need to provide a span to `eval_to_valtree`
     let ecx = mk_eval_cx_to_read_const_val(
         tcx,
         DUMMY_SP,
-        param_env,
+        typing_env,
         // It is absolutely crucial for soundness that
         // we do not read from mutable memory.
         CanAccessMutGlobal::No,
@@ -272,7 +275,8 @@ pub(crate) fn eval_to_valtree<'tcx>(
 #[instrument(skip(tcx), level = "debug", ret)]
 pub fn valtree_to_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
     valtree: ty::ValTree<'tcx>,
 ) -> mir::ConstValue<'tcx> {
     // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
@@ -281,9 +285,6 @@ pub fn valtree_to_const_value<'tcx>(
     // the `ValTree` and using `place_projection` and `place_field` to
     // create inner `MPlace`s which are filled recursively.
     // FIXME Does this need an example?
-
-    let (param_env, ty) = param_env_ty.into_parts();
-
     match *ty.kind() {
         ty::FnDef(..) => {
             assert!(valtree.unwrap_branch().is_empty());
@@ -297,16 +298,17 @@ pub fn valtree_to_const_value<'tcx>(
                 ),
             }
         }
-        ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
+        ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree),
         ty::Ref(_, inner_ty, _) => {
             let mut ecx =
-                mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
+                mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
             let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
-            let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
+            let imm =
+                ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap());
             op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
         }
         ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => {
-            let layout = tcx.layout_of(param_env_ty).unwrap();
+            let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
             if layout.is_zst() {
                 // Fast path to avoid some allocations.
                 return mir::ConstValue::ZeroSized;
@@ -319,16 +321,16 @@ pub fn valtree_to_const_value<'tcx>(
                 let branches = valtree.unwrap_branch();
                 // Find the non-ZST field. (There can be aligned ZST!)
                 for (i, &inner_valtree) in branches.iter().enumerate() {
-                    let field = layout.field(&LayoutCx::new(tcx, param_env), i);
+                    let field = layout.field(&LayoutCx::new(tcx, typing_env), i);
                     if !field.is_zst() {
-                        return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
+                        return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree);
                     }
                 }
                 bug!("could not find non-ZST field during in {layout:#?}");
             }
 
             let mut ecx =
-                mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
+                mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
 
             // Need to create a place for this valtree.
             let place = create_valtree_place(&mut ecx, layout, valtree);
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index ef0902e4226..ed4a1a9e647 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -215,7 +215,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // Even if `ty` is normalized, the search for the unsized tail will project
                 // to fields, which can yield non-normalized types. So we need to provide a
                 // normalization function.
-                let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
+                let normalize = |ty| self.tcx.normalize_erasing_regions(self.typing_env, ty);
                 ty.ptr_metadata_ty(*self.tcx, normalize)
             };
             return interp_ok(meta_ty(caller) == meta_ty(callee));
@@ -662,7 +662,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
                     // (For that reason we also cannot use `unpack_dyn_trait`.)
                     let receiver_tail =
-                        self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env);
+                        self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env);
                     let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
                         span_bug!(
                             self.cur_span(),
@@ -704,7 +704,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                     let concrete_method = Instance::expect_resolve_for_vtable(
                         tcx,
-                        self.param_env,
+                        self.typing_env,
                         def_id,
                         instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
                         self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 49559059265..c95e51f0a1f 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -83,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     ty::FnDef(def_id, args) => {
                         let instance = ty::Instance::resolve_for_fn_ptr(
                             *self.tcx,
-                            self.param_env,
+                            self.typing_env,
                             def_id,
                             args,
                         )
@@ -384,7 +384,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx> {
         // A<Struct> -> A<Trait> conversion
         let (src_pointee_ty, dest_pointee_ty) =
-            self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
+            self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env);
 
         match (src_pointee_ty.kind(), dest_pointee_ty.kind()) {
             (&ty::Array(_, length), &ty::Slice(_)) => {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index ff6d5b28b3b..fe93a48c2f2 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1,18 +1,18 @@
+use std::assert_matches::debug_assert_matches;
+
 use either::{Left, Right};
 use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::at::ToTrace;
-use rustc_infer::traits::{ObligationCause, Reveal};
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
-use rustc_middle::ty::{
-    self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance,
-};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
 use rustc_middle::{mir, span_bug};
 use rustc_session::Limit;
 use rustc_span::Span;
@@ -38,8 +38,9 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> {
     /// we are evaluating (if this is CTFE).
     pub tcx: TyCtxtAt<'tcx>,
 
-    /// Bounds in scope for polymorphic evaluations.
-    pub(crate) param_env: ty::ParamEnv<'tcx>,
+    /// The current context in case we're evaluating in a
+    /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis`.
+    pub(super) typing_env: ty::TypingEnv<'tcx>,
 
     /// The virtual memory system.
     pub memory: Memory<'tcx, M>,
@@ -65,12 +66,12 @@ where
     }
 }
 
-impl<'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'tcx, M>
+impl<'tcx, M> layout::HasTypingEnv<'tcx> for InterpCx<'tcx, M>
 where
     M: Machine<'tcx>,
 {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
     }
 }
 
@@ -116,8 +117,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     src: TyAndLayout<'tcx>,
     dest: TyAndLayout<'tcx>,
 ) -> bool {
@@ -125,7 +125,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
     // all normal lifetimes are erased, higher-ranked types with their
     // late-bound lifetimes are still around and can lead to type
     // differences.
-    if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, src.ty, dest.ty) {
+    if util::relate_types(tcx, typing_env, Variance::Covariant, src.ty, dest.ty) {
         // Make sure the layout is equal, too -- just to be safe. Miri really
         // needs layout equality. For performance reason we skip this check when
         // the types are equal. Equal types *can* have different layouts when
@@ -145,8 +145,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
 #[cfg_attr(not(debug_assertions), inline(always))]
 pub(super) fn from_known_layout<'tcx>(
     tcx: TyCtxtAt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     known_layout: Option<TyAndLayout<'tcx>>,
     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -155,13 +154,7 @@ pub(super) fn from_known_layout<'tcx>(
         Some(known_layout) => {
             if cfg!(debug_assertions) {
                 let check_layout = compute()?;
-                if !mir_assign_valid_types(
-                    tcx.tcx,
-                    typing_mode,
-                    param_env,
-                    check_layout,
-                    known_layout,
-                ) {
+                if !mir_assign_valid_types(tcx.tcx, typing_env, check_layout, known_layout) {
                     span_bug!(
                         tcx.span,
                         "expected type differs from actual type.\nexpected: {}\nactual: {}",
@@ -199,23 +192,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn new(
         tcx: TyCtxt<'tcx>,
         root_span: Span,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         machine: M,
     ) -> Self {
+        // Const eval always happens in post analysis mode in order to be able to use the hidden types of
+        // opaque types. This is needed for trivial things like `size_of`, but also for using associated
+        // types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
+        // already been revealed, so we'd be able to at least partially observe the hidden types anyways.
+        debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
         InterpCx {
             machine,
             tcx: tcx.at(root_span),
-            param_env,
+            typing_env,
             memory: Memory::new(),
             recursion_limit: tcx.recursion_limit(),
         }
     }
 
-    pub fn typing_mode(&self) -> TypingMode<'tcx> {
-        debug_assert_eq!(self.param_env.reveal(), Reveal::All);
-        TypingMode::PostAnalysis
-    }
-
     /// Returns the span of the currently executed statement/terminator.
     /// This is the span typically used for error reporting.
     #[inline(always)]
@@ -258,7 +251,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     #[inline]
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(*self.tcx, self.param_env)
+        ty.is_freeze(*self.tcx, self.typing_env)
     }
 
     pub fn load_mir(
@@ -304,22 +297,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             .instance
             .try_instantiate_mir_and_normalize_erasing_regions(
                 *self.tcx,
-                self.param_env,
+                self.typing_env,
                 ty::EarlyBinder::bind(value),
             )
             .map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
     }
 
-    /// The `args` are assumed to already be in our interpreter "universe" (param_env).
+    /// The `args` are assumed to already be in our interpreter "universe".
     pub(super) fn resolve(
         &self,
         def: DefId,
         args: GenericArgsRef<'tcx>,
     ) -> InterpResult<'tcx, ty::Instance<'tcx>> {
         trace!("resolve: {:?}, {:#?}", def, args);
-        trace!("param_env: {:#?}", self.param_env);
+        trace!("typing_env: {:#?}", self.typing_env);
         trace!("args: {:#?}", args);
-        match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) {
+        match ty::Instance::try_resolve(*self.tcx, self.typing_env, def, args) {
             Ok(Some(instance)) => interp_ok(instance),
             Ok(None) => throw_inval!(TooGeneric),
 
@@ -328,7 +321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
-    /// Check if the two things are equal in the current param_env, using an infctx to get proper
+    /// Check if the two things are equal in the current param_env, using an infcx to get proper
     /// equality checks.
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool
@@ -340,14 +333,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return true;
         }
         // Slow path: spin up an inference context to check if these traits are sufficiently equal.
-        let infcx = self.tcx.infer_ctxt().build(self.typing_mode());
+        let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
         let ocx = ObligationCtxt::new(&infcx);
         let cause = ObligationCause::dummy_with_span(self.cur_span());
         // equate the two trait refs after normalization
-        let a = ocx.normalize(&cause, self.param_env, a);
-        let b = ocx.normalize(&cause, self.param_env, b);
+        let a = ocx.normalize(&cause, param_env, a);
+        let b = ocx.normalize(&cause, param_env, b);
 
-        if let Err(terr) = ocx.eq(&cause, self.param_env, a, b) {
+        if let Err(terr) = ocx.eq(&cause, param_env, a, b) {
             trace!(?terr);
             return false;
         }
@@ -572,10 +565,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let val = if self.tcx.is_static(gid.instance.def_id()) {
             let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id());
 
-            let ty = instance.ty(self.tcx.tcx, self.param_env);
+            let ty = instance.ty(self.tcx.tcx, self.typing_env);
             mir::ConstAlloc { alloc_id, ty }
         } else {
-            self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))?
+            self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.typing_env.as_query_input(gid)))?
         };
         self.raw_const_to_mplace(val)
     }
@@ -587,7 +580,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
-            let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
+            let const_val = val.eval(*ecx.tcx, ecx.typing_env, span).map_err(|err| {
                 if M::ALL_CONSTS_ARE_PRECHECKED {
                     match err {
                         ErrorHandled::TooGeneric(..) => {},
@@ -596,6 +589,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                                 // const-eval will return "tainted" errors if e.g. the layout cannot
                                 // be computed as the type references non-existing names.
                                 // See <https://github.com/rust-lang/rust/issues/124348>.
+                            } else if reported.can_be_spurious() {
+                                // These errors can just sometimes happen, even when the expression
+                                // is nominally "infallible", e.g. when running out of memory.
                             } else {
                                 // Looks like the const is not captured by `required_consts`, that's bad.
                                 span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts");
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 7a1b92601a4..0cbb3b157f3 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -165,7 +165,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
         InternKind::Static(Mutability::Not) => {
             (
                 // Outermost allocation is mutable if `!Freeze`.
-                if ret.layout.ty.is_freeze(*ecx.tcx, ecx.param_env) {
+                if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) {
                     Mutability::Not
                 } else {
                     Mutability::Mut
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index c7a56a80e81..a79923e8555 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -34,7 +34,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
 /// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
 pub(crate) fn eval_nullary_intrinsic<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     def_id: DefId,
     args: GenericArgsRef<'tcx>,
 ) -> InterpResult<'tcx, ConstValue<'tcx>> {
@@ -48,11 +48,13 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
         }
         sym::needs_drop => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
-            ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env))
+            ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env))
         }
         sym::pref_align_of => {
             // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
-            let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?;
+            let layout = tcx
+                .layout_of(typing_env.as_query_input(tp_ty))
+                .map_err(|e| err_inval!(Layout(*e)))?;
             ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
         }
         sym::type_id => {
@@ -149,8 +151,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     sym::type_name => Ty::new_static_str(self.tcx.tcx),
                     _ => bug!(),
                 };
-                let val =
-                    self.ctfe_query(|tcx| tcx.const_eval_global_id(self.param_env, gid, tcx.span))?;
+                let val = self
+                    .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?;
                 let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
                 self.copy_op(&val, dest)?;
             }
@@ -355,7 +357,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                 let should_panic = !self
                     .tcx
-                    .check_validity_requirement((requirement, self.param_env.and(ty)))
+                    .check_validity_requirement((requirement, self.typing_env.as_query_input(ty)))
                     .map_err(|_| err_inval!(TooGeneric))?;
 
                 if should_panic {
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 09635c96e57..277d293597a 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -859,8 +859,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // # Global allocations
         if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
-            let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);
-            let mutbl = global_alloc.mutability(*self.tcx, self.param_env);
+            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::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
                 GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index a130ae89bcb..0157e6c2125 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -8,7 +8,7 @@ use rustc_abi as abi;
 use rustc_abi::{BackendRepr, HasDataLayout, Size};
 use rustc_hir::def::Namespace;
 use rustc_middle::mir::interpret::ScalarSizeMismatch;
-use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
 use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir, span_bug, ty};
@@ -297,21 +297,25 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
-        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap();
+        let layout = tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
+            .unwrap();
         Self::from_scalar(Scalar::from_bool(b), layout)
     }
 
     #[inline]
     pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
         let ty = tcx.ty_ordering_enum(None);
-        let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+        let layout =
+            tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
         Self::from_scalar(Scalar::from_i8(c as i8), layout)
     }
 
     pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
         let layout = tcx
             .layout_of(
-                ty::ParamEnv::reveal_all().and(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
+                ty::TypingEnv::fully_monomorphized()
+                    .as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
             )
             .unwrap();
         Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
@@ -341,7 +345,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
-    pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>)) -> (Self, Self) {
+    pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>)) -> (Self, Self) {
         let layout = self.layout;
         let (val0, val1) = self.to_scalar_pair();
         (
@@ -773,8 +777,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 )?;
             if !mir_assign_valid_types(
                 *self.tcx,
-                self.typing_mode(),
-                self.param_env,
+                self.typing_env(),
                 self.layout_of(normalized_place_ty)?,
                 op.layout,
             ) {
@@ -833,9 +836,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             })
         };
         let layout =
-            from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
-                self.layout_of(ty).into()
-            })?;
+            from_known_layout(self.tcx, self.typing_env(), layout, || self.layout_of(ty).into())?;
         let imm = match val_val {
             mir::ConstValue::Indirect { alloc_id, offset } => {
                 // This is const data, no mutation allowed.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index fbc85d37953..1fa5dcbd24f 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -533,7 +533,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
             OffsetOf(fields) => {
                 let val =
-                    self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
+                    self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes();
                 ImmTy::from_uint(val, usize_layout())
             }
             UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx),
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index cc8d1db6cfb..2beec544fad 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -540,8 +540,7 @@ where
                 )?;
             if !mir_assign_valid_types(
                 *self.tcx,
-                self.typing_mode(),
-                self.param_env,
+                self.typing_env,
                 self.layout_of(normalized_place_ty)?,
                 place.layout,
             ) {
@@ -871,13 +870,8 @@ where
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        let layout_compat = mir_assign_valid_types(
-            *self.tcx,
-            self.typing_mode(),
-            self.param_env,
-            src.layout(),
-            dest.layout(),
-        );
+        let layout_compat =
+            mir_assign_valid_types(*self.tcx, self.typing_env, src.layout(), dest.layout());
         if !allow_transmute && !layout_compat {
             span_bug!(
                 self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 50c0446b3cd..8ce11c71b8b 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -379,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         for &const_ in body.required_consts() {
             let c =
                 self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
-            c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
+            c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| {
                 err.emit_note(*self.tcx);
                 err
             })?;
@@ -596,13 +596,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return interp_ok(layout);
         }
 
-        let layout =
-            from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
-                let local_ty = frame.body.local_decls[local].ty;
-                let local_ty =
-                    self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
-                self.layout_of(local_ty).into()
-            })?;
+        let layout = from_known_layout(self.tcx, self.typing_env, layout, || {
+            let local_ty = frame.body.local_decls[local].ty;
+            let local_ty =
+                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+            self.layout_of(local_ty).into()
+        })?;
 
         // Layouts of locals are requested a lot, so we cache them.
         state.layout.set(Some(layout));
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 18cff2c5e0f..b61865be667 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -143,6 +143,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
+
+            // Only used for temporary lifetime lints
+            BackwardIncompatibleDropHint { .. } => {}
         }
 
         interp_ok(())
@@ -418,7 +421,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             .collect::<InterpResult<'tcx, Vec<_>>>()?;
 
         let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
+        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, fn_sig_binder);
         let extra_args = &args[fn_sig.inputs().len()..];
         let extra_args =
             self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 3a68db9f7f7..273eaf42d87 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -448,7 +448,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         meta: MemPlaceMeta<M::Provenance>,
         pointee: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx> {
-        let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env);
+        let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env);
         match tail.kind() {
             ty::Dynamic(data, _, ty::Dyn) => {
                 let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
@@ -568,7 +568,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                         throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
                     };
                     let (size, _align) =
-                        global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env);
+                        global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env);
 
                     if let GlobalAlloc::Static(did) = global_alloc {
                         let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
@@ -619,7 +619,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                         };
                         // Determine what it actually points to.
                         let alloc_actual_mutbl =
-                            global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env);
+                            global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env);
                         // Mutable pointer to immutable memory is no good.
                         if ptr_expected_mutbl == Mutability::Mut
                             && alloc_actual_mutbl == Mutability::Not
@@ -848,7 +848,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
             if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
                 let tcx = *self.ecx.tcx;
                 // Everything must be already interned.
-                let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env);
+                let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.typing_env);
                 if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) {
                     assert_eq!(alloc.mutability, mutbl);
                 }
@@ -955,7 +955,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     ) -> Cow<'e, RangeSet> {
         assert!(layout.ty.is_union());
         assert!(layout.is_sized(), "there are no unsized unions");
-        let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
+        let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env);
         return M::cached_union_data_range(ecx, layout.ty, || {
             let mut out = RangeSet(Vec::new());
             union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out);
@@ -1085,7 +1085,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
     ) -> InterpResult<'tcx> {
         // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory.
         if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
-            if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) {
+            if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env)
+            {
                 if !self.in_mutable_memory(val) {
                     throw_validation_failure!(self.path, UnsafeCellInImmutable);
                 }
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 0490195caf4..2a7408f1c70 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -40,14 +40,13 @@ pub fn provide(providers: &mut Providers) {
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.eval_static_initializer = const_eval::eval_static_initializer_provider;
     providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider;
-    providers.eval_to_valtree = |tcx, param_env_and_value| {
-        let (param_env, raw) = param_env_and_value.into_parts();
-        const_eval::eval_to_valtree(tcx, param_env, raw)
+    providers.eval_to_valtree = |tcx, ty::PseudoCanonicalInput { typing_env, value }| {
+        const_eval::eval_to_valtree(tcx, typing_env, value)
     };
     providers.hooks.try_destructure_mir_constant_for_user_output =
         const_eval::try_destructure_mir_constant_for_user_output;
     providers.valtree_to_const_val = |tcx, (ty, valtree)| {
-        const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree)
+        const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree)
     };
     providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
         util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index 6fa7d369229..9507b24f603 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -9,7 +9,7 @@ use tracing::debug;
 pub fn is_disaligned<'tcx, L>(
     tcx: TyCtxt<'tcx>,
     local_decls: &L,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     place: Place<'tcx>,
 ) -> bool
 where
@@ -22,8 +22,8 @@ where
     };
 
     let ty = place.ty(local_decls, tcx).ty;
-    let unsized_tail = || tcx.struct_tail_for_codegen(ty, param_env);
-    match tcx.layout_of(param_env.and(ty)) {
+    let unsized_tail = || tcx.struct_tail_for_codegen(ty, typing_env);
+    match tcx.layout_of(typing_env.as_query_input(ty)) {
         Ok(layout)
             if layout.align.abi <= pack
                 && (layout.is_sized()
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 7f4c36835e4..9bf16d4fe16 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -60,7 +60,7 @@ pub(crate) fn const_caller_location_provider(
     let mut ecx = mk_eval_cx_to_read_const_val(
         tcx.tcx,
         tcx.span,
-        ty::ParamEnv::reveal_all(),
+        ty::TypingEnv::fully_monomorphized(),
         CanAccessMutGlobal::No,
     );
 
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 f743525f359..651a797e97c 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -3,7 +3,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::layout::{
     HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement,
 };
-use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt};
 
 use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine};
 use crate::interpret::{InterpCx, MemoryKind};
@@ -23,16 +23,16 @@ use crate::interpret::{InterpCx, MemoryKind};
 pub fn check_validity_requirement<'tcx>(
     tcx: TyCtxt<'tcx>,
     kind: ValidityRequirement,
-    param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
+    input: PseudoCanonicalInput<'tcx, Ty<'tcx>>,
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
-    let layout = tcx.layout_of(param_env_and_ty)?;
+    let layout = tcx.layout_of(input)?;
 
     // There is nothing strict or lax about inhabitedness.
     if kind == ValidityRequirement::Inhabited {
         return Ok(!layout.is_uninhabited());
     }
 
-    let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
+    let layout_cx = LayoutCx::new(tcx, input.typing_env);
     if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
         check_validity_requirement_strict(layout, &layout_cx, kind)
     } else {
@@ -49,7 +49,7 @@ fn check_validity_requirement_strict<'tcx>(
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
 
-    let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine);
+    let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.typing_env, machine);
 
     let allocated = cx
         .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 0cf27d30c36..9eed1a20f15 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -5,18 +5,17 @@
 
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
+use rustc_middle::ty::{Ty, TyCtxt, TypingEnv, Variance};
 use rustc_trait_selection::traits::ObligationCtxt;
 
 /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
 pub fn sub_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     src: Ty<'tcx>,
     dest: Ty<'tcx>,
 ) -> bool {
-    relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest)
+    relate_types(tcx, typing_env, Variance::Covariant, src, dest)
 }
 
 /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
@@ -26,8 +25,7 @@ pub fn sub_types<'tcx>(
 /// because we want to check for type equality.
 pub fn relate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    typing_mode: TypingMode<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     variance: Variance,
     src: Ty<'tcx>,
     dest: Ty<'tcx>,
@@ -36,8 +34,7 @@ pub fn relate_types<'tcx>(
         return true;
     }
 
-    let mut builder = tcx.infer_ctxt().ignoring_regions();
-    let infcx = builder.build(typing_mode);
+    let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
     let ocx = ObligationCtxt::new(&infcx);
     let cause = ObligationCause::dummy();
     let src = ocx.normalize(&cause, param_env, src);
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index bede4c49703..65d586124b3 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -21,6 +21,7 @@
 #![feature(auto_traits)]
 #![feature(cfg_match)]
 #![feature(core_intrinsics)]
+#![feature(dropck_eyepatch)]
 #![feature(extend_one)]
 #![feature(file_buffered)]
 #![feature(hash_raw_entry)]
@@ -78,6 +79,7 @@ pub mod thinvec;
 pub mod transitive_relation;
 pub mod unhash;
 pub mod unord;
+pub mod vec_cache;
 pub mod work_queue;
 
 mod atomic_ref;
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
index bafb16a8b5e..34895d3efe6 100644
--- a/compiler/rustc_data_structures/src/unord.rs
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -602,6 +602,11 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
             .into_iter()
             .map(|(_, v)| v)
     }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
 }
 
 impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>
diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs
new file mode 100644
index 00000000000..eb251b587c8
--- /dev/null
+++ b/compiler/rustc_data_structures/src/vec_cache.rs
@@ -0,0 +1,324 @@
+//! VecCache maintains a mapping from K -> (V, I) pairing. K and I must be roughly u32-sized, and V
+//! must be Copy.
+//!
+//! VecCache supports efficient concurrent put/get across the key space, with write-once semantics
+//! (i.e., a given key can only be put once). Subsequent puts will panic.
+//!
+//! This is currently used for query caching.
+
+use std::fmt::Debug;
+use std::marker::PhantomData;
+use std::sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering};
+
+use rustc_index::Idx;
+
+struct Slot<V> {
+    // We never construct &Slot<V> so it's fine for this to not be in an UnsafeCell.
+    value: V,
+    // This is both an index and a once-lock.
+    //
+    // 0: not yet initialized.
+    // 1: lock held, initializing.
+    // 2..u32::MAX - 2: initialized.
+    index_and_lock: AtomicU32,
+}
+
+/// This uniquely identifies a single `Slot<V>` entry in the buckets map, and provides accessors for
+/// either getting the value or putting a value.
+#[derive(Copy, Clone, Debug)]
+struct SlotIndex {
+    // the index of the bucket in VecCache (0 to 20)
+    bucket_idx: usize,
+    // number of entries in that bucket
+    entries: usize,
+    // the index of the slot within the bucket
+    index_in_bucket: usize,
+}
+
+// This makes sure the counts are consistent with what we allocate, precomputing each bucket a
+// compile-time. Visiting all powers of two is enough to hit all the buckets.
+//
+// We confirm counts are accurate in the slot_index_exhaustive test.
+const ENTRIES_BY_BUCKET: [usize; 21] = {
+    let mut entries = [0; 21];
+    let mut key = 0;
+    loop {
+        let si = SlotIndex::from_index(key);
+        entries[si.bucket_idx] = si.entries;
+        if key == 0 {
+            key = 1;
+        } else if key == (1 << 31) {
+            break;
+        } else {
+            key <<= 1;
+        }
+    }
+    entries
+};
+
+impl SlotIndex {
+    // This unpacks a flat u32 index into identifying which bucket it belongs to and the offset
+    // within that bucket. As noted in the VecCache docs, buckets double in size with each index.
+    // Typically that would mean 31 buckets (2^0 + 2^1 ... + 2^31 = u32::MAX - 1), but to reduce
+    // the size of the VecCache struct and avoid uselessly small allocations, we instead have the
+    // first bucket have 2**12 entries. To simplify the math, the second bucket also 2**12 entries,
+    // and buckets double from there.
+    //
+    // We assert that [0, 2**32 - 1] uniquely map through this function to individual, consecutive
+    // slots (see `slot_index_exhaustive` in tests).
+    #[inline]
+    const fn from_index(idx: u32) -> Self {
+        let mut bucket = match idx.checked_ilog2() {
+            Some(x) => x as usize,
+            None => 0,
+        };
+        let entries;
+        let running_sum;
+        if bucket <= 11 {
+            entries = 1 << 12;
+            running_sum = 0;
+            bucket = 0;
+        } else {
+            entries = 1 << bucket;
+            running_sum = entries;
+            bucket = bucket - 11;
+        }
+        SlotIndex { bucket_idx: bucket, entries, index_in_bucket: idx as usize - running_sum }
+    }
+
+    // SAFETY: Buckets must be managed solely by functions here (i.e., get/put on SlotIndex) and
+    // `self` comes from SlotIndex::from_index
+    #[inline]
+    unsafe fn get<V: Copy>(&self, buckets: &[AtomicPtr<Slot<V>>; 21]) -> Option<(V, u32)> {
+        // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e.,
+        // in-bounds of buckets. See `from_index` for computation.
+        let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) };
+        let ptr = bucket.load(Ordering::Acquire);
+        // Bucket is not yet initialized: then we obviously won't find this entry in that bucket.
+        if ptr.is_null() {
+            return None;
+        }
+        assert!(self.index_in_bucket < self.entries);
+        // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this
+        // must be inbounds.
+        let slot = unsafe { ptr.add(self.index_in_bucket) };
+
+        // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for
+        // AtomicU32 access.
+        let index_and_lock = unsafe { &(*slot).index_and_lock };
+        let current = index_and_lock.load(Ordering::Acquire);
+        let index = match current {
+            0 => return None,
+            // Treat "initializing" as actually just not initialized at all.
+            // The only reason this is a separate state is that `complete` calls could race and
+            // we can't allow that, but from load perspective there's no difference.
+            1 => return None,
+            _ => current - 2,
+        };
+
+        // SAFETY:
+        // * slot is a valid pointer (buckets are always valid for the index we get).
+        // * value is initialized since we saw a >= 2 index above.
+        // * `V: Copy`, so safe to read.
+        let value = unsafe { (*slot).value };
+        Some((value, index))
+    }
+
+    fn bucket_ptr<V>(&self, bucket: &AtomicPtr<Slot<V>>) -> *mut Slot<V> {
+        let ptr = bucket.load(Ordering::Acquire);
+        if ptr.is_null() { self.initialize_bucket(bucket) } else { ptr }
+    }
+
+    #[cold]
+    fn initialize_bucket<V>(&self, bucket: &AtomicPtr<Slot<V>>) -> *mut Slot<V> {
+        static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
+
+        // If we are initializing the bucket, then acquire a global lock.
+        //
+        // This path is quite cold, so it's cheap to use a global lock. This ensures that we never
+        // have multiple allocations for the same bucket.
+        let _allocator_guard = LOCK.lock().unwrap_or_else(|e| e.into_inner());
+
+        let ptr = bucket.load(Ordering::Acquire);
+
+        // OK, now under the allocator lock, if we're still null then it's definitely us that will
+        // initialize this bucket.
+        if ptr.is_null() {
+            let bucket_layout =
+                std::alloc::Layout::array::<Slot<V>>(self.entries as usize).unwrap();
+            // This is more of a sanity check -- this code is very cold, so it's safe to pay a
+            // little extra cost here.
+            assert!(bucket_layout.size() > 0);
+            // SAFETY: Just checked that size is non-zero.
+            let allocated = unsafe { std::alloc::alloc_zeroed(bucket_layout).cast::<Slot<V>>() };
+            if allocated.is_null() {
+                std::alloc::handle_alloc_error(bucket_layout);
+            }
+            bucket.store(allocated, Ordering::Release);
+            allocated
+        } else {
+            // Otherwise some other thread initialized this bucket after we took the lock. In that
+            // case, just return early.
+            ptr
+        }
+    }
+
+    /// Returns true if this successfully put into the map.
+    #[inline]
+    fn put<V>(&self, buckets: &[AtomicPtr<Slot<V>>; 21], value: V, extra: u32) -> bool {
+        // SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e.,
+        // in-bounds of buckets.
+        let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) };
+        let ptr = self.bucket_ptr(bucket);
+
+        assert!(self.index_in_bucket < self.entries);
+        // SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this
+        // must be inbounds.
+        let slot = unsafe { ptr.add(self.index_in_bucket) };
+
+        // SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for
+        // AtomicU32 access.
+        let index_and_lock = unsafe { &(*slot).index_and_lock };
+        match index_and_lock.compare_exchange(0, 1, Ordering::AcqRel, Ordering::Acquire) {
+            Ok(_) => {
+                // We have acquired the initialization lock. It is our job to write `value` and
+                // then set the lock to the real index.
+
+                unsafe {
+                    (&raw mut (*slot).value).write(value);
+                }
+
+                index_and_lock.store(extra.checked_add(2).unwrap(), Ordering::Release);
+
+                true
+            }
+
+            // Treat "initializing" as the caller's fault. Callers are responsible for ensuring that
+            // there are no races on initialization. In the compiler's current usage for query
+            // caches, that's the "active query map" which ensures each query actually runs once
+            // (even if concurrently started).
+            Err(1) => panic!("caller raced calls to put()"),
+
+            // This slot was already populated. Also ignore, currently this is the same as
+            // "initializing".
+            Err(_) => false,
+        }
+    }
+}
+
+pub struct VecCache<K: Idx, V, I> {
+    // Entries per bucket:
+    // Bucket  0:       4096 2^12
+    // Bucket  1:       4096 2^12
+    // Bucket  2:       8192
+    // Bucket  3:      16384
+    // ...
+    // Bucket 19: 1073741824
+    // Bucket 20: 2147483648
+    // The total number of entries if all buckets are initialized is u32::MAX-1.
+    buckets: [AtomicPtr<Slot<V>>; 21],
+
+    // In the compiler's current usage these are only *read* during incremental and self-profiling.
+    // They are an optimization over iterating the full buckets array.
+    present: [AtomicPtr<Slot<()>>; 21],
+    len: AtomicUsize,
+
+    key: PhantomData<(K, I)>,
+}
+
+impl<K: Idx, V, I> Default for VecCache<K, V, I> {
+    fn default() -> Self {
+        VecCache {
+            buckets: Default::default(),
+            key: PhantomData,
+            len: Default::default(),
+            present: Default::default(),
+        }
+    }
+}
+
+// SAFETY: No access to `V` is made.
+unsafe impl<K: Idx, #[may_dangle] V, I> Drop for VecCache<K, V, I> {
+    fn drop(&mut self) {
+        // We have unique ownership, so no locks etc. are needed. Since `K` and `V` are both `Copy`,
+        // we are also guaranteed to just need to deallocate any large arrays (not iterate over
+        // contents).
+        //
+        // Confirm no need to deallocate invidual entries. Note that `V: Copy` is asserted on
+        // insert/lookup but not necessarily construction, primarily to avoid annoyingly propagating
+        // the bounds into struct definitions everywhere.
+        assert!(!std::mem::needs_drop::<K>());
+        assert!(!std::mem::needs_drop::<V>());
+
+        for (idx, bucket) in self.buckets.iter().enumerate() {
+            let bucket = bucket.load(Ordering::Acquire);
+            if !bucket.is_null() {
+                let layout = std::alloc::Layout::array::<Slot<V>>(ENTRIES_BY_BUCKET[idx]).unwrap();
+                unsafe {
+                    std::alloc::dealloc(bucket.cast(), layout);
+                }
+            }
+        }
+
+        for (idx, bucket) in self.present.iter().enumerate() {
+            let bucket = bucket.load(Ordering::Acquire);
+            if !bucket.is_null() {
+                let layout = std::alloc::Layout::array::<Slot<()>>(ENTRIES_BY_BUCKET[idx]).unwrap();
+                unsafe {
+                    std::alloc::dealloc(bucket.cast(), layout);
+                }
+            }
+        }
+    }
+}
+
+impl<K, V, I> VecCache<K, V, I>
+where
+    K: Eq + Idx + Copy + Debug,
+    V: Copy,
+    I: Idx + Copy,
+{
+    #[inline(always)]
+    pub fn lookup(&self, key: &K) -> Option<(V, I)> {
+        let key = u32::try_from(key.index()).unwrap();
+        let slot_idx = SlotIndex::from_index(key);
+        match unsafe { slot_idx.get(&self.buckets) } {
+            Some((value, idx)) => Some((value, I::new(idx as usize))),
+            None => None,
+        }
+    }
+
+    #[inline]
+    pub fn complete(&self, key: K, value: V, index: I) {
+        let key = u32::try_from(key.index()).unwrap();
+        let slot_idx = SlotIndex::from_index(key);
+        if slot_idx.put(&self.buckets, value, index.index() as u32) {
+            let present_idx = self.len.fetch_add(1, Ordering::Relaxed);
+            let slot = SlotIndex::from_index(present_idx as u32);
+            // We should always be uniquely putting due to `len` fetch_add returning unique values.
+            assert!(slot.put(&self.present, (), key));
+        }
+    }
+
+    pub fn iter(&self, f: &mut dyn FnMut(&K, &V, I)) {
+        for idx in 0..self.len.load(Ordering::Acquire) {
+            let key = SlotIndex::from_index(idx as u32);
+            match unsafe { key.get(&self.present) } {
+                // This shouldn't happen in our current usage (iter is really only
+                // used long after queries are done running), but if we hit this in practice it's
+                // probably fine to just break early.
+                None => unreachable!(),
+                Some(((), key)) => {
+                    let key = K::new(key as usize);
+                    // unwrap() is OK: present entries are always written only after we put the real
+                    // entry.
+                    let value = self.lookup(&key).unwrap();
+                    f(&key, &value.0, value.1);
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/vec_cache/tests.rs b/compiler/rustc_data_structures/src/vec_cache/tests.rs
new file mode 100644
index 00000000000..a05f2741362
--- /dev/null
+++ b/compiler/rustc_data_structures/src/vec_cache/tests.rs
@@ -0,0 +1,95 @@
+use super::*;
+
+#[test]
+#[cfg(not(miri))]
+fn vec_cache_empty() {
+    let cache: VecCache<u32, u32, u32> = VecCache::default();
+    for key in 0..u32::MAX {
+        assert!(cache.lookup(&key).is_none());
+    }
+}
+
+#[test]
+fn vec_cache_insert_and_check() {
+    let cache: VecCache<u32, u32, u32> = VecCache::default();
+    cache.complete(0, 1, 2);
+    assert_eq!(cache.lookup(&0), Some((1, 2)));
+}
+
+#[test]
+fn sparse_inserts() {
+    let cache: VecCache<u32, u8, u32> = VecCache::default();
+    let end = if cfg!(target_pointer_width = "64") && cfg!(target_os = "linux") {
+        // For paged memory, 64-bit systems we should be able to sparsely allocate all of the pages
+        // needed for these inserts cheaply (without needing to actually have gigabytes of resident
+        // memory).
+        31
+    } else {
+        // Otherwise, still run the test but scaled back:
+        //
+        // Each slot is 5 bytes, so 2^25 entries (on non-virtual memory systems, like e.g. Windows) will
+        // mean 160 megabytes of allocated memory. Going beyond that is probably not reasonable for
+        // tests.
+        25
+    };
+    for shift in 0..end {
+        let key = 1u32 << shift;
+        cache.complete(key, shift, key);
+        assert_eq!(cache.lookup(&key), Some((shift, key)));
+    }
+}
+
+#[test]
+fn concurrent_stress_check() {
+    let cache: VecCache<u32, u32, u32> = VecCache::default();
+    std::thread::scope(|s| {
+        for idx in 0..100 {
+            let cache = &cache;
+            s.spawn(move || {
+                cache.complete(idx, idx, idx);
+            });
+        }
+    });
+
+    for idx in 0..100 {
+        assert_eq!(cache.lookup(&idx), Some((idx, idx)));
+    }
+}
+
+#[test]
+fn slot_entries_table() {
+    assert_eq!(ENTRIES_BY_BUCKET, [
+        4096, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304,
+        8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824,
+        2147483648
+    ]);
+}
+
+#[test]
+#[cfg(not(miri))]
+fn slot_index_exhaustive() {
+    let mut buckets = [0u32; 21];
+    for idx in 0..=u32::MAX {
+        buckets[SlotIndex::from_index(idx).bucket_idx] += 1;
+    }
+    let mut prev = None::<SlotIndex>;
+    for idx in 0..=u32::MAX {
+        let slot_idx = SlotIndex::from_index(idx);
+        if let Some(p) = prev {
+            if p.bucket_idx == slot_idx.bucket_idx {
+                assert_eq!(p.index_in_bucket + 1, slot_idx.index_in_bucket);
+            } else {
+                assert_eq!(slot_idx.index_in_bucket, 0);
+            }
+        } else {
+            assert_eq!(idx, 0);
+            assert_eq!(slot_idx.index_in_bucket, 0);
+            assert_eq!(slot_idx.bucket_idx, 0);
+        }
+
+        assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries as u32);
+        assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries, "{}", idx);
+
+        prev = Some(slot_idx);
+    }
+}
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index 31837e01764..05e11c4527f 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -23,3 +23,5 @@ driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc ver
 driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
 
 driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
+
+driver_impl_unstable_feature_usage = cannot dump feature usage metrics: {$error}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b6f7abed6f3..c270ce16726 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -15,6 +15,7 @@
 #![feature(panic_update_hook)]
 #![feature(result_flattening)]
 #![feature(rustdoc_internals)]
+#![feature(try_blocks)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
@@ -50,6 +51,7 @@ use rustc_interface::{Linker, Queries, interface, passes};
 use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
+use rustc_middle::ty::TyCtxt;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::config::{
     CG_OPTIONS, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, Z_OPTIONS,
@@ -102,7 +104,7 @@ mod signal_handler {
 
 use crate::session_diagnostics::{
     RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
-    RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead,
+    RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage,
 };
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
@@ -430,6 +432,10 @@ fn run_compiler(
             // Make sure name resolution and macro expansion is run.
             queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering());
 
+            if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
+                queries.global_ctxt()?.enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir));
+            }
+
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
@@ -474,6 +480,23 @@ fn run_compiler(
     })
 }
 
+fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &PathBuf) {
+    let output_filenames = tcxt.output_filenames(());
+    let mut metrics_file_name = std::ffi::OsString::from("unstable_feature_usage_metrics-");
+    let mut metrics_path = output_filenames.with_directory_and_extension(metrics_dir, "json");
+    let metrics_file_stem =
+        metrics_path.file_name().expect("there should be a valid default output filename");
+    metrics_file_name.push(metrics_file_stem);
+    metrics_path.pop();
+    metrics_path.push(metrics_file_name);
+    if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
+        // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit
+        // default metrics" to only produce a warning when metrics are enabled by default and emit
+        // an error only when the user manually enables metrics
+        tcxt.dcx().emit_err(UnstableFeatureUsage { error });
+    }
+}
+
 // Extract output directory and file from matches.
 fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileName>) {
     let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
@@ -564,71 +587,63 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col
     }
 }
 
-/// If color is always or auto, print formatted & colorized markdown. If color is never or
-/// if formatted printing fails, print the raw text.
+/// If `color` is `always` or `auto`, try to print pretty (formatted & colorized) markdown. If
+/// that fails or `color` is `never`, print the raw markdown.
 ///
-/// Prefers a pager, falls back standard print
+/// Uses a pager if possible, falls back to stdout.
 fn show_md_content_with_pager(content: &str, color: ColorConfig) {
-    let mut fallback_to_println = false;
     let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
         if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
     });
 
     let mut cmd = Command::new(&pager_name);
-    // FIXME: find if other pagers accept color options
-    let mut print_formatted = if pager_name == "less" {
-        cmd.arg("-r");
-        true
-    } else {
-        ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name)
-    };
-
-    if color == ColorConfig::Never {
-        print_formatted = false;
-    } else if color == ColorConfig::Always {
-        print_formatted = true;
-    }
-
-    let mdstream = markdown::MdStream::parse_str(content);
-    let bufwtr = markdown::create_stdout_bufwtr();
-    let mut mdbuf = bufwtr.buffer();
-    if mdstream.write_termcolor_buf(&mut mdbuf).is_err() {
-        print_formatted = false;
+    if pager_name == "less" {
+        cmd.arg("-R"); // allows color escape sequences
     }
 
-    if let Ok(mut pager) = cmd.stdin(Stdio::piped()).spawn() {
-        if let Some(pipe) = pager.stdin.as_mut() {
-            let res = if print_formatted {
-                pipe.write_all(mdbuf.as_slice())
-            } else {
-                pipe.write_all(content.as_bytes())
-            };
-
-            if res.is_err() {
-                fallback_to_println = true;
-            }
+    let pretty_on_pager = match color {
+        ColorConfig::Auto => {
+            // Add other pagers that accept color escape sequences here.
+            ["less", "bat", "batcat", "delta"].iter().any(|v| *v == pager_name)
         }
+        ColorConfig::Always => true,
+        ColorConfig::Never => false,
+    };
 
-        if pager.wait().is_err() {
-            fallback_to_println = true;
-        }
-    } else {
-        fallback_to_println = true;
-    }
+    // Try to prettify the raw markdown text. The result can be used by the pager or on stdout.
+    let pretty_data = {
+        let mdstream = markdown::MdStream::parse_str(content);
+        let bufwtr = markdown::create_stdout_bufwtr();
+        let mut mdbuf = bufwtr.buffer();
+        if mdstream.write_termcolor_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None }
+    };
+
+    // Try to print via the pager, pretty output if possible.
+    let pager_res: Option<()> = try {
+        let mut pager = cmd.stdin(Stdio::piped()).spawn().ok()?;
 
-    // If pager fails for whatever reason, we should still print the content
-    // to standard output
-    if fallback_to_println {
-        let fmt_success = match color {
-            ColorConfig::Auto => io::stdout().is_terminal() && bufwtr.print(&mdbuf).is_ok(),
-            ColorConfig::Always => bufwtr.print(&mdbuf).is_ok(),
-            ColorConfig::Never => false,
+        let pager_stdin = pager.stdin.as_mut()?;
+        if pretty_on_pager && let Some((_, mdbuf)) = &pretty_data {
+            pager_stdin.write_all(mdbuf.as_slice()).ok()?;
+        } else {
+            pager_stdin.write_all(content.as_bytes()).ok()?;
         };
 
-        if !fmt_success {
-            safe_print!("{content}");
-        }
+        pager.wait().ok()?;
+    };
+    if pager_res.is_some() {
+        return;
+    }
+
+    // The pager failed. Try to print pretty output to stdout.
+    if let Some((bufwtr, mdbuf)) = &pretty_data
+        && bufwtr.print(&mdbuf).is_ok()
+    {
+        return;
     }
+
+    // Everything failed. Print the raw markdown text.
+    safe_print!("{content}");
 }
 
 fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
index 449878f28c4..e06c56539d1 100644
--- a/compiler/rustc_driver_impl/src/session_diagnostics.rs
+++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs
@@ -1,3 +1,5 @@
+use std::error::Error;
+
 use rustc_macros::{Diagnostic, Subdiagnostic};
 
 #[derive(Diagnostic)]
@@ -93,3 +95,9 @@ pub(crate) struct IceFlags {
 #[derive(Diagnostic)]
 #[diag(driver_impl_ice_exclude_cargo_defaults)]
 pub(crate) struct IceExcludeCargoDefaults;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_unstable_feature_usage)]
+pub(crate) struct UnstableFeatureUsage {
+    pub error: Box<dyn Error>,
+}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 04ac7891023..19c2d466f7c 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1303,7 +1303,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
         fragment.make_trait_items()
     }
     fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        walk_flat_map_item(visitor, self.wrapped)
+        walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
@@ -1344,7 +1344,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
         fragment.make_impl_items()
     }
     fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        walk_flat_map_item(visitor, self.wrapped)
+        walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
@@ -1382,7 +1382,7 @@ impl InvocationCollectorNode for P<ast::ForeignItem> {
         fragment.make_foreign_items()
     }
     fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        walk_flat_map_item(visitor, self)
+        walk_flat_map_foreign_item(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ForeignItemKind::MacCall(..))
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 610c69e9d21..bae16a18bcb 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -286,7 +286,7 @@ impl MutVisitor for PlaceholderExpander {
                     AssocCtxt::Impl => it.make_impl_items(),
                 }
             }
-            _ => walk_flat_map_item(self, item),
+            _ => walk_flat_map_assoc_item(self, item, ctxt),
         }
     }
 
@@ -296,7 +296,7 @@ impl MutVisitor for PlaceholderExpander {
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
         match item.kind {
             ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(),
-            _ => walk_flat_map_item(self, item),
+            _ => walk_flat_map_foreign_item(self, item),
         }
     }
 
diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml
index 9df320e1279..77de7fabd4f 100644
--- a/compiler/rustc_feature/Cargo.toml
+++ b/compiler/rustc_feature/Cargo.toml
@@ -7,4 +7,6 @@ edition = "2021"
 # tidy-alphabetical-start
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_span = { path = "../rustc_span" }
+serde = { version = "1.0.125", features = [ "derive" ] }
+serde_json = "1.0.59"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index a4820ba8b72..fd08b35d242 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -838,7 +838,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
     ),
     rustc_attr!(
-        rustc_const_stable_intrinsic, Normal,
+        rustc_intrinsic_const_stable_indirect, Normal,
         template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
     ),
     gated!(
@@ -880,6 +880,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "lang items are subject to change",
     ),
     rustc_attr!(
+        rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
+    ),
+    rustc_attr!(
         rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
         EncodeCrossCrate::Yes,
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 9f42d3ec45c..5d27b8f542c 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -74,14 +74,19 @@ impl UnstableFeatures {
         // Returns whether `krate` should be counted as unstable
         let is_unstable_crate =
             |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
-        // `true` if we should enable unstable features for bootstrapping.
-        let bootstrap =
-            std::env::var("RUSTC_BOOTSTRAP").is_ok_and(|var| var == "1" || is_unstable_crate(&var));
-        match (disable_unstable_features, bootstrap) {
-            (_, true) => UnstableFeatures::Cheat,
-            (true, _) => UnstableFeatures::Disallow,
-            (false, _) => UnstableFeatures::Allow,
+
+        let bootstrap = std::env::var("RUSTC_BOOTSTRAP").ok();
+        if let Some(val) = bootstrap.as_deref() {
+            match val {
+                val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat,
+                // Hypnotize ourselves so that we think we are a stable compiler and thus don't
+                // allow any unstable features.
+                "-1" => return UnstableFeatures::Disallow,
+                _ => {}
+            }
         }
+
+        if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
     }
 
     pub fn is_nightly_build(&self) -> bool {
diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs
index 50433e44b13..cc0e1f31209 100644
--- a/compiler/rustc_feature/src/tests.rs
+++ b/compiler/rustc_feature/src/tests.rs
@@ -18,6 +18,16 @@ fn rustc_bootstrap_parsing() {
     assert!(!is_bootstrap("x,y,z", Some("a")));
     assert!(!is_bootstrap("x,y,z", None));
 
-    // this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
+    // `RUSTC_BOOTSTRAP=0` is not recognized.
     assert!(!is_bootstrap("0", None));
+
+    // `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed.
+    let is_force_stable = |krate| {
+        std::env::set_var("RUSTC_BOOTSTRAP", "-1");
+        matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Disallow)
+    };
+    assert!(is_force_stable(None));
+    // Does not support specifying any crate.
+    assert!(is_force_stable(Some("x")));
+    assert!(is_force_stable(Some("x,y,z")));
 }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 8326d0031ea..e3dc73c1401 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -1,5 +1,7 @@
 //! List of the unstable feature gates.
 
+use std::path::PathBuf;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
@@ -54,7 +56,7 @@ pub struct EnabledLangFeature {
     pub stable_since: Option<Symbol>,
 }
 
-/// Information abhout an enabled library feature.
+/// Information about an enabled library feature.
 #[derive(Debug, Copy, Clone)]
 pub struct EnabledLibFeature {
     pub gate_name: Symbol,
@@ -529,6 +531,8 @@ declare_features! (
     (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (unstable, marker_trait_attr, "1.30.0", Some(29864)),
+    /// Enables the generic const args MVP (only bare paths, not arbitrary computation).
+    (incomplete, min_generic_const_args, "CURRENT_RUSTC_VERSION", Some(132980)),
     /// A minimal, sound subset of specialization intended to be used by the
     /// standard library until the soundness issues with specialization
     /// are fixed.
@@ -649,6 +653,54 @@ declare_features! (
     // -------------------------------------------------------------------------
 );
 
+impl Features {
+    pub fn dump_feature_usage_metrics(
+        &self,
+        metrics_path: PathBuf,
+    ) -> Result<(), Box<dyn std::error::Error>> {
+        #[derive(serde::Serialize)]
+        struct LibFeature {
+            symbol: String,
+        }
+
+        #[derive(serde::Serialize)]
+        struct LangFeature {
+            symbol: String,
+            since: Option<String>,
+        }
+
+        #[derive(serde::Serialize)]
+        struct FeatureUsage {
+            lib_features: Vec<LibFeature>,
+            lang_features: Vec<LangFeature>,
+        }
+
+        let metrics_file = std::fs::File::create(metrics_path)?;
+        let metrics_file = std::io::BufWriter::new(metrics_file);
+
+        let lib_features = self
+            .enabled_lib_features
+            .iter()
+            .map(|EnabledLibFeature { gate_name, .. }| LibFeature { symbol: gate_name.to_string() })
+            .collect();
+
+        let lang_features = self
+            .enabled_lang_features
+            .iter()
+            .map(|EnabledLangFeature { gate_name, stable_since, .. }| LangFeature {
+                symbol: gate_name.to_string(),
+                since: stable_since.map(|since| since.to_string()),
+            })
+            .collect();
+
+        let feature_usage = FeatureUsage { lib_features, lang_features };
+
+        serde_json::to_writer(metrics_file, &feature_usage)?;
+
+        Ok(())
+    }
+}
+
 /// Some features are not allowed to be used together at the same time, if
 /// the two are present, produce an error.
 ///
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 6e8ba51612e..64a30e633cf 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -448,6 +448,11 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match
     .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
     .feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
 
+hir_analysis_rpitit_refined_lifetimes = impl trait in impl method captures fewer lifetimes than in trait
+    .suggestion = modify the `use<..>` bound to capture the same lifetimes that the trait does
+    .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+    .feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+
 hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 3080d8b3510..cf3f3003bf5 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -21,8 +21,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
 use rustc_middle::ty::{
-    AdtDef, GenericArgKind, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt,
+    AdtDef, GenericArgKind, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_session::lint::builtin::UNINHABITED_STATIC;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -91,38 +90,38 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
         fn allowed_union_field<'tcx>(
             ty: Ty<'tcx>,
             tcx: TyCtxt<'tcx>,
-            param_env: ty::ParamEnv<'tcx>,
+            typing_env: ty::TypingEnv<'tcx>,
         ) -> bool {
             // We don't just accept all !needs_drop fields, due to semver concerns.
             match ty.kind() {
                 ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
                 ty::Tuple(tys) => {
                     // allow tuples of allowed types
-                    tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env))
+                    tys.iter().all(|ty| allowed_union_field(ty, tcx, typing_env))
                 }
                 ty::Array(elem, _len) => {
                     // Like `Copy`, we do *not* special-case length 0.
-                    allowed_union_field(*elem, tcx, param_env)
+                    allowed_union_field(*elem, tcx, typing_env)
                 }
                 _ => {
                     // Fallback case: allow `ManuallyDrop` and things that are `Copy`,
                     // also no need to report an error if the type is unresolved.
                     ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
-                        || ty.is_copy_modulo_regions(tcx, param_env)
+                        || ty.is_copy_modulo_regions(tcx, typing_env)
                         || ty.references_error()
                 }
             }
         }
 
-        let param_env = tcx.param_env(item_def_id);
+        let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
         for field in &def.non_enum_variant().fields {
-            let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args))
+            let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args))
             else {
                 tcx.dcx().span_delayed_bug(span, "could not normalize field type");
                 continue;
             };
 
-            if !allowed_union_field(field_ty, tcx, param_env) {
+            if !allowed_union_field(field_ty, tcx, typing_env) {
                 let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
                     // We are currently checking the type this field came from, so it must be local.
                     Some(Node::Field(field)) => (field.span, field.ty.span),
@@ -137,7 +136,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                     note: (),
                 });
                 return false;
-            } else if field_ty.needs_drop(tcx, param_env) {
+            } else if field_ty.needs_drop(tcx, typing_env) {
                 // This should never happen. But we can get here e.g. in case of name resolution errors.
                 tcx.dcx()
                     .span_delayed_bug(span, "we should never accept maybe-dropping union fields");
@@ -158,7 +157,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     // reason to allow any statics to be uninhabited.
     let ty = tcx.type_of(def_id).instantiate_identity();
     let span = tcx.def_span(def_id);
-    let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) {
+    let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
         Ok(l) => l,
         // Foreign statics that overflow their allowed size should emit an error
         Err(LayoutError::SizeOverflow(_))
@@ -237,7 +236,10 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 
         // And also look for cycle errors in the layout of coroutines.
         if let Err(&LayoutError::Cycle(guar)) =
-            tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args)))
+            tcx.layout_of(
+                ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
+                    .as_query_input(Ty::new_opaque(tcx, def_id.to_def_id(), args)),
+            )
         {
             return Err(guar);
         }
@@ -337,6 +339,8 @@ fn check_opaque_meets_bounds<'tcx>(
 
     let misc_cause = ObligationCause::misc(span, def_id);
     // FIXME: We should just register the item bounds here, rather than equating.
+    // FIXME(const_trait_impl): When we do that, please make sure to also register
+    // the `~const` bounds.
     match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
         Ok(()) => {}
         Err(ty_err) => {
@@ -1307,8 +1311,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
     // "known" respecting #[non_exhaustive] attributes.
     let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
-        let param_env = tcx.param_env(field.did);
-        let layout = tcx.layout_of(param_env.and(ty));
+        let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did);
+        let layout = tcx.layout_of(typing_env.as_query_input(ty));
         // We are currently checking the type this field came from, so it must be local
         let span = tcx.hir().span_if_local(field.did).unwrap();
         let trivial = layout.is_ok_and(|layout| layout.is_1zst());
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 77c324183c3..bd0b0ceb92d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1193,9 +1193,9 @@ fn compare_self_type<'tcx>(
             ty::AssocItemContainer::Trait => tcx.types.self_param,
         };
         let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0);
-        let param_env = ty::ParamEnv::reveal_all();
-
-        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
+        let (infcx, param_env) = tcx
+            .infer_ctxt()
+            .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id));
         let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
         let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty);
         match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
@@ -2083,7 +2083,7 @@ pub(super) fn check_type_bounds<'tcx>(
     // Only in a const implementation do we need to check that the `~const` item bounds hold.
     if tcx.is_conditionally_const(impl_ty_def_id) {
         obligations.extend(
-            tcx.implied_const_bounds(trait_ty.def_id)
+            tcx.explicit_implied_const_bounds(trait_ty.def_id)
                 .iter_instantiated_copied(tcx, rebased_args)
                 .map(|(c, span)| {
                     traits::Obligation::new(
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 646c104f1f5..25ba52b4d7b 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -1,6 +1,7 @@
+use itertools::Itertools as _;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
@@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     let mut trait_bounds = vec![];
     // Bounds that we find on the RPITITs in the impl signature.
     let mut impl_bounds = vec![];
+    // Pairs of trait and impl opaques.
+    let mut pairs = vec![];
 
     for trait_projection in collector.types.into_iter().rev() {
         let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
@@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
             tcx.explicit_item_bounds(impl_opaque.def_id)
                 .iter_instantiated_copied(tcx, impl_opaque.args),
         ));
+
+        pairs.push((trait_projection, impl_opaque));
     }
 
     let hybrid_preds = tcx
@@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
             return;
         }
     }
+
+    // Make sure that the RPITIT doesn't capture fewer regions than
+    // the trait definition. We hard-error if it captures *more*, since that
+    // is literally unrepresentable in the type system; however, we may be
+    // promising stronger outlives guarantees if we capture *fewer* regions.
+    for (trait_projection, impl_opaque) in pairs {
+        let impl_variances = tcx.variances_of(impl_opaque.def_id);
+        let impl_captures: FxIndexSet<_> = impl_opaque
+            .args
+            .iter()
+            .zip_eq(impl_variances)
+            .filter(|(_, v)| **v == ty::Invariant)
+            .map(|(arg, _)| arg)
+            .collect();
+
+        let trait_variances = tcx.variances_of(trait_projection.def_id);
+        let mut trait_captures = FxIndexSet::default();
+        for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) {
+            if *variance != ty::Invariant {
+                continue;
+            }
+            arg.visit_with(&mut CollectParams { params: &mut trait_captures });
+        }
+
+        if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) {
+            report_mismatched_rpitit_captures(
+                tcx,
+                impl_opaque.def_id.expect_local(),
+                trait_captures,
+                is_internal,
+            );
+        }
+    }
 }
 
 struct ImplTraitInTraitCollector<'tcx> {
@@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
         self.tcx.anonymize_bound_vars(t)
     }
 }
+
+struct CollectParams<'a, 'tcx> {
+    params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>,
+}
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) {
+        if let ty::Param(_) = ty.kind() {
+            self.params.insert(ty.into());
+        } else {
+            ty.super_visit_with(self);
+        }
+    }
+    fn visit_region(&mut self, r: ty::Region<'tcx>) {
+        match r.kind() {
+            ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
+                self.params.insert(r.into());
+            }
+            _ => {}
+        }
+    }
+    fn visit_const(&mut self, ct: ty::Const<'tcx>) {
+        if let ty::ConstKind::Param(_) = ct.kind() {
+            self.params.insert(ct.into());
+        } else {
+            ct.super_visit_with(self);
+        }
+    }
+}
+
+fn report_mismatched_rpitit_captures<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_opaque_def_id: LocalDefId,
+    mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>,
+    is_internal: bool,
+) {
+    let Some(use_bound_span) =
+        tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map(
+            |bound| match *bound {
+                rustc_hir::GenericBound::Use(_, span) => Some(span),
+                hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None,
+            },
+        )
+    else {
+        // I have no idea when you would ever undercapture without a `use<..>`.
+        tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque");
+        return;
+    };
+
+    trait_captured_args
+        .sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_)));
+    let suggestion = format!("use<{}>", trait_captured_args.iter().join(", "));
+
+    tcx.emit_node_span_lint(
+        if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE },
+        tcx.local_def_id_to_hir_id(impl_opaque_def_id),
+        use_bound_span,
+        crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes {
+            suggestion_span: use_bound_span,
+            suggestion,
+        },
+    );
+}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index cb954b0adcb..3e33120901f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -109,9 +109,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::three_way_compare
         | sym::discriminant_value
         | sym::type_id
-        | sym::likely
-        | sym::unlikely
         | sym::select_unpredictable
+        | sym::cold_path
         | sym::ptr_guaranteed_cmp
         | sym::minnumf16
         | sym::minnumf32
@@ -489,9 +488,8 @@ pub fn check_intrinsic_type(
             sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
 
             sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit),
-            sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
-            sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
             sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)),
+            sym::cold_path => (0, 0, vec![], tcx.types.unit),
 
             sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
             sym::write_via_move => {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index e95669c9d40..dfddf93a5c2 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -15,7 +15,7 @@ use rustc_target::asm::{
 
 pub struct InlineAsmCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
 }
 
@@ -23,24 +23,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self {
         InlineAsmCtxt {
             tcx,
-            param_env: ty::ParamEnv::empty(),
+            typing_env: ty::TypingEnv {
+                typing_mode: ty::TypingMode::non_body_analysis(),
+                param_env: ty::ParamEnv::empty(),
+            },
             get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
         }
     }
 
+    // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their
+    // defining scope.
     pub fn new_in_fn(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
     ) -> Self {
-        InlineAsmCtxt { tcx, param_env, get_operand_ty: Box::new(get_operand_ty) }
+        InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) }
     }
 
     // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
     fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
         // Type still may have region variables, but `Sized` does not depend
         // on those, so just erase them before querying.
-        if ty.is_sized(self.tcx, self.param_env) {
+        if ty.is_sized(self.tcx, self.typing_env) {
             return true;
         }
         if let ty::Foreign(..) = ty.kind() {
@@ -171,7 +176,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
 
         // Check that the type implements Copy. The only case where this can
         // possibly fail is for SIMD types which don't #[derive(Copy)].
-        if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
+        if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) {
             let msg = "arguments for inline assembly must be copyable";
             self.tcx
                 .dcx()
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 679f6ccb816..b9cb48cafdc 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -17,6 +17,7 @@ use rustc_index::Idx;
 use rustc_middle::bug;
 use rustc_middle::middle::region::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::lint;
 use rustc_span::source_map;
 use tracing::debug;
 
@@ -167,8 +168,23 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
             }
         }
         if let Some(tail_expr) = blk.expr {
-            if blk.span.edition().at_least_rust_2024() {
-                visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
+            let local_id = tail_expr.hir_id.local_id;
+            let edition = blk.span.edition();
+            if edition.at_least_rust_2024() {
+                visitor.terminating_scopes.insert(local_id);
+            } else if !visitor
+                .tcx
+                .lints_that_dont_need_to_run(())
+                .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER))
+            {
+                // If this temporary scope will be changing once the codebase adopts Rust 2024,
+                // and we are linting about possible semantic changes that would result,
+                // then record this node-id in the field `backwards_incompatible_scope`
+                // for future reference.
+                visitor
+                    .scope_tree
+                    .backwards_incompatible_scope
+                    .insert(local_id, Scope { id: local_id, data: ScopeData::Node });
             }
             visitor.visit_expr(tail_expr);
         }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 1802f00bc1f..20bc34b8c79 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1126,7 +1126,7 @@ fn check_type_defn<'tcx>(
                     let ty = tcx.type_of(variant.tail().did).instantiate_identity();
                     let ty = tcx.erase_regions(ty);
                     assert!(!ty.has_infer());
-                    ty.needs_drop(tcx, tcx.param_env(item.owner_id))
+                    ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env))
                 }
             };
             // All fields (except for possibly the last) should be sized.
@@ -1281,7 +1281,8 @@ fn check_item_type(
             UnsizedHandling::Forbid => true,
             UnsizedHandling::Allow => false,
             UnsizedHandling::AllowIfForeignTail => {
-                let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.param_env);
+                let tail =
+                    tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env));
                 !matches!(tail.kind(), ty::Foreign(_))
             }
         };
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 5ff52376837..3b49bc41ffe 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let lang_items = tcx.lang_items();
     let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
-    let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
-    res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
-    res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
+    checker.check(lang_items.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)
-    }));
-    res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
+    })?;
+    checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
         visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
-    }));
-
-    res = res.and(
-        checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
-    );
-    res.and(
-        checker
-            .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
-    )
+    })?;
+    checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
+    checker
+        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
+    checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
+    Ok(())
 }
 
 struct Checker<'tcx> {
@@ -259,7 +256,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                     let ty_a = field.ty(tcx, args_a);
                     let ty_b = field.ty(tcx, args_b);
 
-                    if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
+                    if let Ok(layout) =
+                        tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
+                    {
                         if layout.is_1zst() {
                             // ignore 1-ZST fields
                             return false;
@@ -661,3 +660,63 @@ fn infringing_fields_error<'tcx>(
 
     err.emit()
 }
+
+fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
+    let tcx = checker.tcx;
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
+    let impl_span = tcx.def_span(checker.impl_def_id);
+    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
+
+    // If an ADT is repr(transparent)...
+    if let ty::Adt(def, args) = *self_ty.kind()
+        && def.repr().transparent()
+    {
+        // FIXME(compiler-errors): This should and could be deduplicated into a query.
+        // Find the nontrivial field.
+        let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did());
+        let nontrivial_field = def.all_fields().find(|field_def| {
+            let field_ty = tcx.type_of(field_def.did).instantiate_identity();
+            !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
+                .is_ok_and(|layout| layout.layout.is_1zst())
+        });
+
+        if let Some(nontrivial_field) = nontrivial_field {
+            // Check that the nontrivial field implements `PointerLike`.
+            let nontrivial_field = nontrivial_field.ty(tcx, args);
+            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+            let ocx = ObligationCtxt::new(&infcx);
+            ocx.register_bound(
+                ObligationCause::misc(impl_span, checker.impl_def_id),
+                param_env,
+                nontrivial_field,
+                tcx.lang_items().pointer_like().unwrap(),
+            );
+            // FIXME(dyn-star): We should regionck this implementation.
+            if ocx.select_all_or_error().is_empty() {
+                return Ok(());
+            }
+        }
+    }
+
+    let is_permitted_primitive = match *self_ty.kind() {
+        ty::Adt(def, _) => def.is_box(),
+        ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
+        _ => false,
+    };
+
+    if is_permitted_primitive
+        && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
+        && layout.layout.is_pointer_like(&tcx.data_layout)
+    {
+        return Ok(());
+    }
+
+    Err(tcx
+        .dcx()
+        .struct_span_err(
+            impl_span,
+            "implementation must be applied to type that has the same ABI as a pointer, \
+            or is `repr(transparent)` and whose field is `PointerLike`",
+        )
+        .emit())
+}
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 8a1a887766c..eca85c22a40 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -172,7 +172,7 @@ pub(crate) fn orphan_check_impl(
             // impl<T> AutoTrait for T {}
             // impl<T: ?Sized> AutoTrait for T {}
             ty::Param(..) => (
-                if self_ty.is_sized(tcx, tcx.param_env(impl_def_id)) {
+                if self_ty.is_sized(tcx, ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) {
                     LocalImpl::Allow
                 } else {
                     LocalImpl::Disallow { problematic_kind: "generic type" }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 63a0e7d31c3..73b73afb0a5 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -46,7 +46,7 @@ use tracing::{debug, instrument};
 
 use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::errors;
-use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
+use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
 
 pub(crate) mod dump;
 mod generics_of;
@@ -78,7 +78,7 @@ pub fn provide(providers: &mut Providers) {
             predicates_of::explicit_supertraits_containing_assoc_item,
         trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
         const_conditions: predicates_of::const_conditions,
-        implied_const_bounds: predicates_of::implied_const_bounds,
+        explicit_implied_const_bounds: predicates_of::explicit_implied_const_bounds,
         type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
         adt_def,
@@ -88,6 +88,7 @@ pub fn provide(providers: &mut Providers) {
         coroutine_for_closure,
         opaque_ty_origin,
         rendered_precise_capturing_args,
+        const_param_default,
         ..*providers
     };
 }
@@ -339,6 +340,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
         self.tcx.ensure().explicit_item_super_predicates(def_id);
         self.tcx.ensure().item_bounds(def_id);
         self.tcx.ensure().item_super_predicates(def_id);
+        if self.tcx.is_conditionally_const(def_id) {
+            self.tcx.ensure().explicit_implied_const_bounds(def_id);
+            self.tcx.ensure().const_conditions(def_id);
+        }
         intravisit::walk_opaque_ty(self, opaque);
     }
 
@@ -681,6 +686,10 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 tcx.ensure().generics_of(item.owner_id);
                 tcx.ensure().type_of(item.owner_id);
                 tcx.ensure().predicates_of(item.owner_id);
+                if tcx.is_conditionally_const(def_id) {
+                    tcx.ensure().explicit_implied_const_bounds(def_id);
+                    tcx.ensure().const_conditions(def_id);
+                }
                 match item.kind {
                     hir::ForeignItemKind::Fn(..) => {
                         tcx.ensure().codegen_fn_attrs(item.owner_id);
@@ -1790,3 +1799,23 @@ fn rendered_precise_capturing_args<'tcx>(
         _ => None,
     })
 }
+
+fn const_param_default<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
+    let default_ct = match tcx.hir_node_by_def_id(def_id) {
+        hir::Node::GenericParam(hir::GenericParam {
+            kind: hir::GenericParamKind::Const { default: Some(ct), .. },
+            ..
+        }) => ct,
+        _ => span_bug!(
+            tcx.def_span(def_id),
+            "`const_param_default` expected a generic parameter with a constant"
+        ),
+    };
+    let icx = ItemCtxt::new(tcx, def_id);
+    // FIXME(const_generics): investigate which places do and don't need const ty feeding
+    let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No);
+    ty::EarlyBinder::bind(ct)
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 7ce12d48160..b5dee5bd021 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -223,11 +223,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 trace!(?predicates);
             }
             hir::GenericParamKind::Const { .. } => {
+                let param_def_id = param.def_id.to_def_id();
                 let ct_ty = tcx
-                    .type_of(param.def_id.to_def_id())
+                    .type_of(param_def_id)
                     .no_bound_vars()
                     .expect("const parameters cannot be generic");
-                let ct = icx.lowerer().lower_const_param(param.hir_id);
+                let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id);
                 predicates
                     .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));
             }
@@ -958,6 +959,12 @@ pub(super) fn const_conditions<'tcx>(
             hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
             _ => bug!("const_conditions called on wrong item: {def_id:?}"),
         },
+        Node::OpaqueTy(opaque) => match opaque.origin {
+            hir::OpaqueTyOrigin::FnReturn { parent, .. } => return tcx.const_conditions(parent),
+            hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => {
+                unreachable!()
+            }
+        },
         // N.B. Tuple ctors are unconditionally constant.
         Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
         _ => bug!("const_conditions called on wrong item: {def_id:?}"),
@@ -1017,7 +1024,7 @@ pub(super) fn const_conditions<'tcx>(
     }
 }
 
-pub(super) fn implied_const_bounds<'tcx>(
+pub(super) fn explicit_implied_const_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
 ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
@@ -1033,10 +1040,11 @@ pub(super) fn implied_const_bounds<'tcx>(
                 PredicateFilter::SelfConstIfConst,
             )
         }
-        Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => {
+        Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
+        | Node::OpaqueTy(_) => {
             explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
         }
-        _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"),
+        _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),
     };
 
     bounds.map_bound(|bounds| {
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 cc55f57c46c..b4b3ef31f97 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -177,6 +177,7 @@ enum Scope<'a> {
     LateBoundary {
         s: ScopeRef<'a>,
         what: &'static str,
+        deny_late_regions: bool,
     },
 
     Root {
@@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
                 .field("s", &"..")
                 .finish(),
             Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
-            Scope::LateBoundary { s: _, what } => {
-                f.debug_struct("LateBoundary").field("what", what).finish()
-            }
+            Scope::LateBoundary { s: _, what, deny_late_regions } => f
+                .debug_struct("LateBoundary")
+                .field("what", what)
+                .field("deny_late_regions", deny_late_regions)
+                .finish(),
             Scope::Root { opt_parent_item } => {
                 f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
             }
@@ -573,17 +576,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             // give, we will reverse the IndexMap after early captures.
             let mut late_depth = 0;
             let mut scope = self.scope;
-            let mut crossed_late_boundary = None;
             let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
             loop {
                 match *scope {
                     Scope::Binder { ref bound_vars, scope_type, s, .. } => {
                         for (&original_lifetime, &def) in bound_vars.iter().rev() {
-                            if let ResolvedArg::LateBound(..) = def
-                                && crossed_late_boundary.is_some()
-                            {
-                                continue;
-                            }
                             if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
                                 let def = def.shifted(late_depth);
                                 let ident = lifetime_ident(original_lifetime);
@@ -624,12 +621,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
                     Scope::ObjectLifetimeDefault { s, .. }
                     | Scope::Supertrait { s, .. }
-                    | Scope::TraitRefBoundary { s, .. } => {
-                        scope = s;
-                    }
-
-                    Scope::LateBoundary { s, what, .. } => {
-                        crossed_late_boundary = Some(what);
+                    | Scope::TraitRefBoundary { s, .. }
+                    | Scope::LateBoundary { s, .. } => {
                         scope = s;
                     }
                 }
@@ -640,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
         let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
         self.with(scope, |this| {
             let scope = Scope::TraitRefBoundary { s: this.scope };
-            this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
+            this.with(scope, |this| {
+                let scope = Scope::LateBoundary {
+                    s: this.scope,
+                    what: "nested `impl Trait`",
+                    // We can capture late-bound regions; we just don't duplicate
+                    // lifetime or const params, so we can't allow those.
+                    deny_late_regions: false,
+                };
+                this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
+            })
         });
 
         let captures = captures.into_inner().into_iter().collect();
@@ -997,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
-        self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
-            intravisit::walk_anon_const(this, c);
-        });
+        self.with(
+            Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true },
+            |this| {
+                intravisit::walk_anon_const(this, c);
+            },
+        );
     }
 
     fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
@@ -1291,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     scope = s;
                 }
 
-                Scope::LateBoundary { s, what } => {
-                    crossed_late_boundary = Some(what);
+                Scope::LateBoundary { s, what, deny_late_regions } => {
+                    if deny_late_regions {
+                        crossed_late_boundary = Some(what);
+                    }
                     scope = s;
                 }
             }
@@ -1508,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     scope = s;
                 }
 
-                Scope::LateBoundary { s, what } => {
+                Scope::LateBoundary { s, what, deny_late_regions: _ } => {
                     crossed_late_boundary = Some(what);
                     scope = s;
                 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index a92a5e4278c..07d3273b09c 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1153,6 +1153,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
     pub return_ty: Ty<'tcx>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_analysis_rpitit_refined_lifetimes)]
+#[note]
+#[note(hir_analysis_feedback_note)]
+pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes {
+    #[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")]
+    pub suggestion_span: Span,
+    pub suggestion: String,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_inherent_ty_outside, code = E0390)]
 #[help]
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 1cade402c54..6ebe1cedcaf 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -19,7 +19,9 @@ use tracing::{debug, instrument};
 use super::errors::GenericsArgsErrExtend;
 use crate::bounds::Bounds;
 use crate::errors;
-use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason};
+use crate::hir_ty_lowering::{
+    AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Add a `Sized` bound to the `bounds` if appropriate.
@@ -346,9 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::AssocItemConstraintKind::Equality { term } => {
                 let term = match term {
                     hir::Term::Ty(ty) => self.lower_ty(ty).into(),
-                    hir::Term::Const(ct) => {
-                        ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into()
-                    }
+                    hir::Term::Const(ct) => self.lower_const_arg(ct, FeedConstTy::No).into(),
                 };
 
                 // Find any late-bound regions declared in `ty` that are not
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 92f38a7dde0..39471931461 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -3,7 +3,7 @@ use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err};
 use rustc_hir::{self as hir, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{self, ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 
 use crate::errors;
 
@@ -130,7 +130,7 @@ fn is_valid_cmse_inputs<'tcx>(
     let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
 
     for (index, ty) in fn_sig.inputs().iter().enumerate() {
-        let layout = tcx.layout_of(ParamEnv::reveal_all().and(*ty))?;
+        let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?;
 
         let align = layout.layout.align().abi.bytes();
         let size = layout.layout.size().bytes();
@@ -158,8 +158,10 @@ fn is_valid_cmse_output<'tcx>(
     // this type is only used for layout computation, which does not rely on regions
     let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
 
+    let typing_env = ty::TypingEnv::fully_monomorphized();
+
     let mut ret_ty = fn_sig.output();
-    let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?;
+    let layout = tcx.layout_of(typing_env.as_query_input(ret_ty))?;
     let size = layout.layout.size().bytes();
 
     if size <= 4 {
@@ -182,7 +184,7 @@ fn is_valid_cmse_output<'tcx>(
         for variant_def in adt_def.variants() {
             for field_def in variant_def.fields.iter() {
                 let ty = field_def.ty(tcx, args);
-                let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?;
+                let layout = tcx.layout_of(typing_env.as_query_input(ty))?;
 
                 if !layout.layout.is_1zst() {
                     ret_ty = ty;
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 dd0f250a8e2..4e5a8271e9e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1106,7 +1106,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     .collect::<String>()
             ),
             [(only, _)] => only.to_string(),
-            [] => "this type".to_string(),
+            [] => bug!("expected one segment to deny"),
         };
 
         let arg_spans: Vec<Span> = segments
@@ -1136,7 +1136,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 "s",
             ),
             [only] => (only.to_string(), ""),
-            [] => unreachable!("expected at least one generic to prohibit"),
+            [] => bug!("expected at least one generic to prohibit"),
         };
         let last_span = *arg_spans.last().unwrap();
         let span: MultiSpan = arg_spans.into();
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 6e8a9ded4f3..ae1279d428c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -115,17 +115,22 @@ fn generic_arg_mismatch_err(
             }
         }
         (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
-            // FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too,
-            // this should match against that instead of ::Anon
-            if let hir::ConstArgKind::Anon(anon) = cnst.kind
+            if let hir::ConstArgKind::Path(qpath) = cnst.kind
+                && let rustc_hir::QPath::Resolved(_, path) = qpath
+                && let Res::Def(DefKind::Fn { .. }, id) = path.res
+            {
+                err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
+                err.help("function item types cannot be named directly");
+            } else if let hir::ConstArgKind::Anon(anon) = cnst.kind
                 && let body = tcx.hir().body(anon.body)
                 && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
                     body.value.kind
+                && let Res::Def(DefKind::Fn { .. }, id) = path.res
             {
-                if let Res::Def(DefKind::Fn { .. }, id) = path.res {
-                    err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
-                    err.help("function item types cannot be named directly");
-                }
+                // FIXME(min_generic_const_args): this branch is dead once new const path lowering
+                // (for single-segment paths) is no longer gated
+                err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
+                err.help("function item types cannot be named directly");
             }
         }
         _ => {}
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 ed39708981b..01276abec22 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -30,7 +30,7 @@ use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
 };
 use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{GenericArg, GenericArgs, HirId};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -217,6 +217,23 @@ impl AssocItemQSelf {
     }
 }
 
+/// In some cases, [`hir::ConstArg`]s that are being used in the type system
+/// through const generics need to have their type "fed" to them
+/// using the query system.
+///
+/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
+/// desired behavior.
+#[derive(Debug, Clone, Copy)]
+pub enum FeedConstTy {
+    /// Feed the type.
+    ///
+    /// The `DefId` belongs to the const param that we are supplying
+    /// this (anon) const arg to.
+    Param(DefId),
+    /// Don't feed the type.
+    No,
+}
+
 /// New-typed boolean indicating whether explicit late-bound lifetimes
 /// are present in a set of generic arguments.
 ///
@@ -500,8 +517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         handle_ty_args(has_default, &inf.to_ty())
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
-                        ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id))
-                            .into()
+                        self.lowerer.lower_const_arg(ct, FeedConstTy::Param(param.def_id)).into()
                     }
                     (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
                         self.lowerer.ct_infer(Some(param), inf.span).into()
@@ -979,8 +995,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 let term: ty::Term<'_> = match term {
                                     hir::Term::Ty(ty) => self.lower_ty(ty).into(),
                                     hir::Term::Const(ct) => {
-                                        ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No)
-                                            .into()
+                                        self.lower_const_arg(ct, FeedConstTy::No).into()
                                     }
                                 };
                                 // FIXME(#97583): This isn't syntactically well-formed!
@@ -2025,23 +2040,138 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///
     /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`]
     /// and late-bound ones to [`ty::ConstKind::Bound`].
-    pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> {
+    pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> {
         let tcx = self.tcx();
-        match tcx.named_bound_var(hir_id) {
-            Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
+
+        match tcx.named_bound_var(path_hir_id) {
+            Some(rbv::ResolvedArg::EarlyBound(_)) => {
                 // Find the name and index of the const parameter by indexing the generics of
                 // the parent item and construct a `ParamConst`.
-                let item_def_id = tcx.local_parent(def_id);
+                let item_def_id = tcx.parent(param_def_id);
                 let generics = tcx.generics_of(item_def_id);
-                let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-                let name = tcx.item_name(def_id.to_def_id());
+                let index = generics.param_def_id_to_index[&param_def_id];
+                let name = tcx.item_name(param_def_id);
                 ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
             }
             Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
                 ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
             }
             Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
-            arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
+            arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id),
+        }
+    }
+
+    /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const).
+    #[instrument(skip(self), level = "debug")]
+    pub fn lower_const_arg(
+        &self,
+        const_arg: &hir::ConstArg<'tcx>,
+        feed: FeedConstTy,
+    ) -> Const<'tcx> {
+        let tcx = self.tcx();
+
+        if let FeedConstTy::Param(param_def_id) = feed
+            && let hir::ConstArgKind::Anon(anon) = &const_arg.kind
+        {
+            tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
+        }
+
+        let hir_id = const_arg.hir_id;
+        match const_arg.kind {
+            hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
+                debug!(?maybe_qself, ?path);
+                let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
+                self.lower_const_path_resolved(opt_self_ty, path, hir_id)
+            }
+            hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message(
+                tcx,
+                qpath.span(),
+                format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
+            ),
+            hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id),
+        }
+    }
+
+    fn lower_const_path_resolved(
+        &self,
+        opt_self_ty: Option<Ty<'tcx>>,
+        path: &hir::Path<'tcx>,
+        hir_id: HirId,
+    ) -> Const<'tcx> {
+        let tcx = self.tcx();
+        let span = path.span;
+        match path.res {
+            Res::Def(DefKind::ConstParam, def_id) => {
+                assert_eq!(opt_self_ty, None);
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::Param(def_id),
+                );
+                self.lower_const_param(def_id, hir_id)
+            }
+            Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => {
+                assert_eq!(opt_self_ty, None);
+                let _ = self.prohibit_generic_args(
+                    path.segments.split_last().unwrap().1.iter(),
+                    GenericsArgsErrExtend::None,
+                );
+                let args = self.lower_generic_args_of_path_segment(
+                    span,
+                    did,
+                    path.segments.last().unwrap(),
+                );
+                ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
+            }
+            Res::Def(DefKind::Static { .. }, _) => {
+                span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported")
+            }
+            // FIXME(const_generics): create real const to allow fn items as const paths
+            Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message(
+                tcx,
+                span,
+                "fn items cannot be used as const args",
+            ),
+
+            // Exhaustive match to be clear about what exactly we're considering to be
+            // an invalid Res for a const path.
+            Res::Def(
+                DefKind::Mod
+                | DefKind::Enum
+                | DefKind::Variant
+                | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
+                | DefKind::Struct
+                | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
+                | DefKind::OpaqueTy
+                | DefKind::TyAlias
+                | DefKind::TraitAlias
+                | DefKind::AssocTy
+                | DefKind::Union
+                | DefKind::Trait
+                | DefKind::ForeignTy
+                | DefKind::AssocConst
+                | DefKind::TyParam
+                | DefKind::Macro(_)
+                | DefKind::LifetimeParam
+                | DefKind::Use
+                | DefKind::ForeignMod
+                | DefKind::AnonConst
+                | DefKind::InlineConst
+                | DefKind::Field
+                | DefKind::Impl { .. }
+                | DefKind::Closure
+                | DefKind::ExternCrate
+                | DefKind::GlobalAsm
+                | DefKind::SyntheticCoroutineBody,
+                _,
+            )
+            | Res::PrimTy(_)
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. }
+            | Res::SelfCtor(_)
+            | Res::Local(_)
+            | Res::ToolMod
+            | Res::NonMacroAttr(_)
+            | Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"),
         }
     }
 
@@ -2053,14 +2183,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    /// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics.
-    ///
-    /// Extra diagnostic data:
-    ///
-    /// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`.
-    ///    Used to avoid emitting redundant errors.
-    /// 2. `in_path`: Whether the type appears inside of a path.
-    ///    Used to provide correct diagnostics for bare trait object types.
+    /// Lower a type from the HIR to our internal notion of a type.
     #[instrument(level = "debug", skip(self), ret)]
     pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
         let tcx = self.tcx();
@@ -2189,7 +2312,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let length = match length {
                     hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
                     hir::ArrayLen::Body(constant) => {
-                        ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No)
+                        self.lower_const_arg(constant, FeedConstTy::No)
                     }
                 };
 
@@ -2247,7 +2370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                         .type_of(def_id)
                                         .no_bound_vars()
                                         .expect("const parameter types cannot be generic");
-                                    let ct = self.lower_const_param(expr.hir_id);
+                                    let ct = self.lower_const_param(def_id, expr.hir_id);
                                     (ct, ty)
                                 }
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 5830636c6e8..0a26b6776bb 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -97,12 +97,14 @@ use rustc_hir::def::DefKind;
 use rustc_middle::middle;
 use rustc_middle::mir::interpret::GlobalId;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_span::Span;
 use rustc_span::symbol::sym;
 use rustc_trait_selection::traits;
 
+use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
+
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 fn require_c_abi_if_c_variadic(
@@ -188,8 +190,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
                 let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
                 let cid = GlobalId { instance, promoted: None };
-                let param_env = ty::ParamEnv::reveal_all();
-                tcx.ensure().eval_to_const_value_raw(param_env.and(cid));
+                let typing_env = ty::TypingEnv::fully_monomorphized();
+                tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid));
             }
             _ => (),
         }
@@ -226,3 +228,14 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
     let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty)
 }
+
+/// This is for rustdoc.
+// FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed
+pub fn lower_const_arg_for_rustdoc<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hir_ct: &hir::ConstArg<'tcx>,
+    feed: FeedConstTy,
+) -> Const<'tcx> {
+    let env_def_id = tcx.hir().get_parent_item(hir_ct.hir_id);
+    collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 354993513da..1610848958e 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2357,8 +2357,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Only assoc fns that return `Self`
                     let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
                     let ret_ty = fn_sig.output();
-                    let ret_ty =
-                        self.tcx.normalize_erasing_late_bound_regions(self.param_env, ret_ty);
+                    let ret_ty = self.tcx.normalize_erasing_late_bound_regions(
+                        self.typing_env(self.param_env),
+                        ret_ty,
+                    );
                     if !self.can_eq(self.param_env, ret_ty, adt_ty) {
                         return None;
                     }
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 59bef8315d8..2a00530c434 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -228,7 +228,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
     }
 
     fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_copy_modulo_regions(self.0.tcx, self.0.param_env)
+        ty.is_copy_modulo_regions(self.0.tcx, self.0.typing_env())
     }
 
     fn body_owner_def_id(&self) -> LocalDefId {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index f0738491609..ce6ce0381a9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -14,8 +14,8 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
     check_generic_arg_count_for_call, lower_generic_args,
 };
 use rustc_hir_analysis::hir_ty_lowering::{
-    ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
-    GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
+    ExplicitLateBound, FeedConstTy, GenericArgCountMismatch, GenericArgCountResult,
+    GenericArgsLowerer, GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
 };
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
@@ -491,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
             hir::ArrayLen::Body(const_arg) => {
                 let span = const_arg.span();
-                let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No);
+                let c = self.lowerer().lower_const_arg(const_arg, FeedConstTy::No);
                 self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
                 self.normalize(span, c)
             }
@@ -503,8 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         const_arg: &'tcx hir::ConstArg<'tcx>,
         param_def_id: DefId,
     ) -> ty::Const<'tcx> {
-        let ct =
-            ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id));
+        let ct = self.lowerer().lower_const_arg(const_arg, FeedConstTy::Param(param_def_id));
         self.register_wf_obligation(
             ct.into(),
             self.tcx.hir().span(const_arg.hir_id),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 50d1322eba6..961526831fb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -105,8 +105,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.tcx.erase_regions(ty)
                 }
             };
-            InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty)
-                .check_asm(asm, enclosing_id);
+            InlineAsmCtxt::new_in_fn(
+                self.tcx,
+                self.infcx.typing_env(self.param_env),
+                get_operand_ty,
+            )
+            .check_asm(asm, enclosing_id);
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 919e83724d7..c4c4c2f200b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2648,15 +2648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
-                        let needs_parens = match expr.kind {
-                            // parenthesize if needed (Issue #46756)
-                            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
-                            // parenthesize borrows of range literals (Issue #54505)
-                            _ if is_range_literal(expr) => true,
-                            _ => false,
-                        };
-
-                        if needs_parens {
+                        if self.needs_parentheses(expr) {
                             (
                                 vec![
                                     (span.shrink_to_lo(), format!("{prefix}{sugg}(")),
@@ -2869,6 +2861,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             return None;
                         }
 
+                        if self.needs_parentheses(expr) {
+                            return Some((
+                                vec![
+                                    (span, format!("{suggestion}(")),
+                                    (expr.span.shrink_to_hi(), ")".to_string()),
+                                ],
+                                message,
+                                Applicability::MachineApplicable,
+                                true,
+                                false,
+                            ));
+                        }
+
                         return Some((
                             vec![(span, suggestion)],
                             message,
@@ -2897,6 +2902,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
+        match expr.kind {
+            // parenthesize if needed (Issue #46756)
+            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+            // parenthesize borrows of range literals (Issue #54505)
+            _ if is_range_literal(expr) => true,
+            _ => false,
+        }
+    }
+
     pub(crate) fn suggest_cast(
         &self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index a754f7fddc9..789530d35dd 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let span = tcx.hir().span(hir_id);
         let normalize = |ty| {
             let ty = self.resolve_vars_if_possible(ty);
-            self.tcx.normalize_erasing_regions(self.param_env, ty)
+            self.tcx.normalize_erasing_regions(self.typing_env(self.param_env), ty)
         };
         let from = normalize(from);
         let to = normalize(to);
@@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
+        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.typing_env(self.param_env));
         let sk_from = skel(from);
         let sk_to = skel(to);
         trace!(?sk_from, ?sk_to);
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 8772599e316..cff2aa68993 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -31,6 +31,7 @@ use rustc_span::symbol::{Ident, kw, sym};
 use rustc_span::{
     DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, edit_distance,
 };
+use rustc_trait_selection::error_reporting::traits::DefIdOrName;
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -45,50 +46,6 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
 use crate::{Expectation, FnCtxt};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        let tcx = self.tcx;
-        match ty.kind() {
-            // Not all of these (e.g., unsafe fns) implement `FnOnce`,
-            // so we look for these beforehand.
-            // FIXME(async_closures): These don't impl `FnOnce` by default.
-            ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(..) => true,
-            // If it's not a simple function, look for things which implement `FnOnce`.
-            _ => {
-                let Some(fn_once) = tcx.lang_items().fn_once_trait() else {
-                    return false;
-                };
-
-                // This conditional prevents us from asking to call errors and unresolved types.
-                // It might seem that we can use `predicate_must_hold_modulo_regions`,
-                // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
-                // type resolution always gives a "maybe" here.
-                if self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
-                    info!("check deref {:?} error", ty);
-                    matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
-                }) {
-                    return false;
-                }
-
-                self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
-                    info!("check deref {:?} impl FnOnce", ty);
-                    self.probe(|_| {
-                        let trait_ref =
-                            ty::TraitRef::new(tcx, fn_once, [ty, self.next_ty_var(span)]);
-                        let poly_trait_ref = ty::Binder::dummy(trait_ref);
-                        let obligation = Obligation::misc(
-                            tcx,
-                            span,
-                            self.body_id,
-                            self.param_env,
-                            poly_trait_ref,
-                        );
-                        self.predicate_may_hold(&obligation)
-                    })
-                })
-            }
-        }
-    }
-
     fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
         self.autoderef(span, ty)
             .silence_errors()
@@ -2367,12 +2324,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let is_accessible = field.vis.is_accessible_from(scope, tcx);
 
             if is_accessible {
-                if self.is_fn_ty(field_ty, span) {
+                if let Some((what, _, _)) = self.extract_callable_info(field_ty) {
+                    let what = match what {
+                        DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
+                        DefIdOrName::Name(what) => what,
+                    };
                     let expr_span = expr.span.to(item_name.span);
                     err.multipart_suggestion(
                         format!(
-                            "to call the function stored in `{item_name}`, \
-                                         surround the field access with parentheses",
+                            "to call the {what} stored in `{item_name}`, \
+                            surround the field access with parentheses",
                         ),
                         vec![
                             (expr_span.shrink_to_lo(), '('.to_string()),
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 175fca327f3..d50eff0deb0 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -1257,7 +1257,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Option<FxIndexSet<UpvarMigrationInfo>> {
         let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
-        if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id)) {
+        // FIXME(#132279): Using `non_body_analysis` here feels wrong.
+        if !ty.has_significant_drop(
+            self.tcx,
+            ty::TypingEnv::non_body_analysis(self.tcx, closure_def_id),
+        ) {
             debug!("does not have significant drop");
             return None;
         }
@@ -1535,8 +1539,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base_path_ty: Ty<'tcx>,
         captured_by_move_projs: Vec<&[Projection<'tcx>]>,
     ) -> bool {
-        let needs_drop =
-            |ty: Ty<'tcx>| ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id));
+        // FIXME(#132279): Using `non_body_analysis` here feels wrong.
+        let needs_drop = |ty: Ty<'tcx>| {
+            ty.has_significant_drop(
+                self.tcx,
+                ty::TypingEnv::non_body_analysis(self.tcx, closure_def_id),
+            )
+        };
 
         let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
             let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 391e640f8bc..2f436ce77a4 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -831,8 +831,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
 
         // Normalize consts in writeback, because GCE doesn't normalize eagerly.
         if tcx.features().generic_const_exprs() {
-            value =
-                value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env });
+            value = value.fold_with(&mut EagerlyNormalizeConsts::new(self.fcx));
         }
 
         value
@@ -873,14 +872,22 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
 
 struct EagerlyNormalizeConsts<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
+impl<'tcx> EagerlyNormalizeConsts<'tcx> {
+    fn new(fcx: &FnCtxt<'_, 'tcx>) -> Self {
+        // FIXME(#132279, generic_const_exprs): Using `try_normalize_erasing_regions` here
+        // means we can't handle opaque types in their defining scope.
+        EagerlyNormalizeConsts { tcx: fcx.tcx, typing_env: fcx.typing_env(fcx.param_env) }
+    }
+}
+
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerlyNormalizeConsts<'tcx> {
     fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        self.tcx.try_normalize_erasing_regions(self.param_env, ct).unwrap_or(ct)
+        self.tcx.try_normalize_erasing_regions(self.typing_env, ct).unwrap_or(ct)
     }
 }
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index c2b9cae680b..a9239489222 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -460,6 +460,10 @@ impl<T: Idx> ChunkedBitSet<T> {
         self.chunks.iter().map(|chunk| chunk.count()).sum()
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.chunks.iter().all(|chunk| matches!(chunk, Chunk::Zeros(..) | Chunk::Ones(0)))
+    }
+
     /// Returns `true` if `self` contains `elem`.
     #[inline]
     pub fn contains(&self, elem: T) -> bool {
@@ -668,12 +672,140 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
         changed
     }
 
-    fn subtract(&mut self, _other: &ChunkedBitSet<T>) -> bool {
-        unimplemented!("implement if/when necessary");
+    fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        debug_assert_eq!(self.chunks.len(), other.chunks.len());
+
+        let mut changed = false;
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
+            match (&mut self_chunk, &other_chunk) {
+                (Zeros(..), _) | (_, Zeros(..)) => {}
+                (
+                    Ones(self_chunk_domain_size) | Mixed(self_chunk_domain_size, _, _),
+                    Ones(other_chunk_domain_size),
+                ) => {
+                    debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size);
+                    changed = true;
+                    *self_chunk = Zeros(*self_chunk_domain_size);
+                }
+                (
+                    Ones(self_chunk_domain_size),
+                    Mixed(other_chunk_domain_size, other_chunk_count, other_chunk_words),
+                ) => {
+                    debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size);
+                    changed = true;
+                    let num_words = num_words(*self_chunk_domain_size as usize);
+                    debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS);
+                    let mut tail_mask =
+                        1 << (*other_chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1;
+                    let mut self_chunk_words = **other_chunk_words;
+                    for word in self_chunk_words[0..num_words].iter_mut().rev() {
+                        *word = !*word & tail_mask;
+                        tail_mask = u64::MAX;
+                    }
+                    let self_chunk_count = *self_chunk_domain_size - *other_chunk_count;
+                    debug_assert_eq!(
+                        self_chunk_count,
+                        self_chunk_words[0..num_words]
+                            .iter()
+                            .map(|w| w.count_ones() as ChunkSize)
+                            .sum()
+                    );
+                    *self_chunk =
+                        Mixed(*self_chunk_domain_size, self_chunk_count, Rc::new(self_chunk_words));
+                }
+                (
+                    Mixed(
+                        self_chunk_domain_size,
+                        ref mut self_chunk_count,
+                        ref mut self_chunk_words,
+                    ),
+                    Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words),
+                ) => {
+                    // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation
+                    let op = |a: u64, b: u64| a & !b;
+                    let num_words = num_words(*self_chunk_domain_size as usize);
+                    if bitwise_changes(
+                        &self_chunk_words[0..num_words],
+                        &other_chunk_words[0..num_words],
+                        op,
+                    ) {
+                        let self_chunk_words = Rc::make_mut(self_chunk_words);
+                        let has_changed = bitwise(
+                            &mut self_chunk_words[0..num_words],
+                            &other_chunk_words[0..num_words],
+                            op,
+                        );
+                        debug_assert!(has_changed);
+                        *self_chunk_count = self_chunk_words[0..num_words]
+                            .iter()
+                            .map(|w| w.count_ones() as ChunkSize)
+                            .sum();
+                        if *self_chunk_count == 0 {
+                            *self_chunk = Zeros(*self_chunk_domain_size);
+                        }
+                        changed = true;
+                    }
+                }
+            }
+        }
+        changed
     }
 
-    fn intersect(&mut self, _other: &ChunkedBitSet<T>) -> bool {
-        unimplemented!("implement if/when necessary");
+    fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        debug_assert_eq!(self.chunks.len(), other.chunks.len());
+
+        let mut changed = false;
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
+            match (&mut self_chunk, &other_chunk) {
+                (Zeros(..), _) | (_, Ones(..)) => {}
+                (
+                    Ones(self_chunk_domain_size),
+                    Zeros(other_chunk_domain_size) | Mixed(other_chunk_domain_size, ..),
+                )
+                | (Mixed(self_chunk_domain_size, ..), Zeros(other_chunk_domain_size)) => {
+                    debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size);
+                    changed = true;
+                    *self_chunk = other_chunk.clone();
+                }
+                (
+                    Mixed(
+                        self_chunk_domain_size,
+                        ref mut self_chunk_count,
+                        ref mut self_chunk_words,
+                    ),
+                    Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words),
+                ) => {
+                    // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation
+                    let op = |a, b| a & b;
+                    let num_words = num_words(*self_chunk_domain_size as usize);
+                    if bitwise_changes(
+                        &self_chunk_words[0..num_words],
+                        &other_chunk_words[0..num_words],
+                        op,
+                    ) {
+                        let self_chunk_words = Rc::make_mut(self_chunk_words);
+                        let has_changed = bitwise(
+                            &mut self_chunk_words[0..num_words],
+                            &other_chunk_words[0..num_words],
+                            op,
+                        );
+                        debug_assert!(has_changed);
+                        *self_chunk_count = self_chunk_words[0..num_words]
+                            .iter()
+                            .map(|w| w.count_ones() as ChunkSize)
+                            .sum();
+                        if *self_chunk_count == 0 {
+                            *self_chunk = Zeros(*self_chunk_domain_size);
+                        }
+                        changed = true;
+                    }
+                }
+            }
+        }
+
+        changed
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 12df4a10e63..b29dc7f909d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -38,7 +38,8 @@ use rustc_middle::ty::fold::{
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
-    GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
+    GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Ty, TyCtxt, TyVid,
+    TypeVisitable, TypingEnv, TypingMode,
 };
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
@@ -565,6 +566,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         (infcx, value, args)
     }
 
+    pub fn build_with_typing_env(
+        mut self,
+        TypingEnv { typing_mode, param_env }: TypingEnv<'tcx>,
+    ) -> (InferCtxt<'tcx>, ty::ParamEnv<'tcx>) {
+        (self.build(typing_mode), param_env)
+    }
+
     pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
         let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } =
             *self;
@@ -1278,6 +1286,42 @@ impl<'tcx> InferCtxt<'tcx> {
         u
     }
 
+    /// Extract [`ty::TypingMode`] of this inference context to get a `TypingEnv`
+    /// which contains the necessary information to use the trait system without
+    /// using canonicalization or carrying this inference context around.
+    pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
+        let typing_mode = match self.typing_mode(param_env) {
+            ty::TypingMode::Coherence => ty::TypingMode::Coherence,
+            // FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible
+            // to handle them without proper canonicalization. This means we may cause cycle
+            // errors and fail to reveal opaques while inside of bodies. We should rename this
+            // function and require explicit comments on all use-sites in the future.
+            ty::TypingMode::Analysis { defining_opaque_types: _ } => {
+                TypingMode::non_body_analysis()
+            }
+            ty::TypingMode::PostAnalysis => ty::TypingMode::PostAnalysis,
+        };
+        ty::TypingEnv { typing_mode, param_env }
+    }
+
+    /// Similar to [`Self::canonicalize_query`], except that it returns
+    /// a [`PseudoCanonicalInput`] and requires both the `value` and the
+    /// `param_env` to not contain any inference variables or placeholders.
+    pub fn pseudo_canonicalize_query<V>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        value: V,
+    ) -> PseudoCanonicalInput<'tcx, V>
+    where
+        V: TypeVisitable<TyCtxt<'tcx>>,
+    {
+        debug_assert!(!value.has_infer());
+        debug_assert!(!value.has_placeholders());
+        debug_assert!(!param_env.has_infer());
+        debug_assert!(!param_env.has_placeholders());
+        self.typing_env(param_env).as_query_input(value)
+    }
+
     /// The returned function is used in a fast path. If it returns `true` the variable is
     /// unchanged, `false` indicates that the status is unknown.
     #[inline]
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index d65ed72a8e8..0aff4620314 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -574,9 +574,8 @@ impl<'tcx> InferCtxt<'tcx> {
         // unexpected region errors.
         goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
 
-        let item_bounds = tcx.explicit_item_bounds(def_id);
-        for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
-            let predicate = predicate.fold_with(&mut BottomUpFolder {
+        let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| {
+            clause.fold_with(&mut BottomUpFolder {
                 tcx,
                 ty_op: |ty| match *ty.kind() {
                     // We can't normalize associated types from `rustc_infer`,
@@ -612,11 +611,31 @@ impl<'tcx> InferCtxt<'tcx> {
                 },
                 lt_op: |lt| lt,
                 ct_op: |ct| ct,
-            });
+            })
+        };
+
+        let item_bounds = tcx.explicit_item_bounds(def_id);
+        for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
+            let predicate = replace_opaques_in(predicate, goals);
 
             // Require that the predicate holds for the concrete type.
             debug!(?predicate);
             goals.push(Goal::new(self.tcx, param_env, predicate));
         }
+
+        // If this opaque is being defined and it's conditionally const,
+        if self.tcx.is_conditionally_const(def_id) {
+            let item_bounds = tcx.explicit_implied_const_bounds(def_id);
+            for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
+                let predicate = replace_opaques_in(
+                    predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe),
+                    goals,
+                );
+
+                // Require that the predicate holds for the concrete type.
+                debug!(?predicate);
+                goals.push(Goal::new(self.tcx, param_env, predicate));
+            }
+        }
     }
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7e629c1d18f..43a98782016 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
 use std::sync::{Arc, LazyLock};
 use std::{env, fs, iter};
 
-use rustc_ast::{self as ast, visit};
+use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
 use rustc_data_structures::steal::Steal;
@@ -24,7 +24,7 @@ use rustc_middle::util::Providers;
 use rustc_parse::{
     new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
 };
-use rustc_passes::{abi_test, hir_stats, layout_test};
+use rustc_passes::{abi_test, input_stats, layout_test};
 use rustc_resolve::Resolver;
 use rustc_session::code_stats::VTableSizeInfo;
 use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
@@ -54,28 +54,17 @@ pub(crate) fn parse<'a>(sess: &'a Session) -> Result<ast::Crate> {
         })
         .map_err(|parse_error| parse_error.emit())?;
 
-    if sess.opts.unstable_opts.input_stats {
-        eprintln!("Lines of code:             {}", sess.source_map().count_lines());
-        eprintln!("Pre-expansion node count:  {}", count_nodes(&krate));
-    }
-
     if let Some(ref s) = sess.opts.unstable_opts.show_span {
         rustc_ast_passes::show_span::run(sess.dcx(), s, &krate);
     }
 
-    if sess.opts.unstable_opts.hir_stats {
-        hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1");
+    if sess.opts.unstable_opts.input_stats {
+        input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1");
     }
 
     Ok(krate)
 }
 
-fn count_nodes(krate: &ast::Crate) -> usize {
-    let mut counter = rustc_ast_passes::node_count::NodeCounter::new();
-    visit::walk_crate(&mut counter, krate);
-    counter.count
-}
-
 fn pre_expansion_lint<'a>(
     sess: &Session,
     features: &Features,
@@ -290,11 +279,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
     let mut lint_buffer = resolver.lint_buffer.steal();
 
     if sess.opts.unstable_opts.input_stats {
-        eprintln!("Post-expansion node count: {}", count_nodes(krate));
-    }
-
-    if sess.opts.unstable_opts.hir_stats {
-        hir_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2");
+        input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2");
     }
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
@@ -820,8 +805,8 @@ pub(crate) fn create_global_ctxt<'tcx>(
 /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
 /// This function never fails.
 fn run_required_analyses(tcx: TyCtxt<'_>) {
-    if tcx.sess.opts.unstable_opts.hir_stats {
-        rustc_passes::hir_stats::print_hir_stats(tcx);
+    if tcx.sess.opts.unstable_opts.input_stats {
+        rustc_passes::input_stats::print_hir_stats(tcx);
     }
     #[cfg(debug_assertions)]
     rustc_passes::hir_id_validator::check_crate(tcx);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 2361231b3fb..e48c4d46b59 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -698,7 +698,6 @@ fn test_unstable_options_tracking_hash() {
     untracked!(dylib_lto, true);
     untracked!(emit_stack_sizes, true);
     untracked!(future_incompat_test, true);
-    untracked!(hir_stats, true);
     untracked!(identify_regions, true);
     untracked!(incremental_info, true);
     untracked!(incremental_verify_ich, true);
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index f9f2a14dbd2..bcb103957ba 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -57,11 +57,10 @@ impl Token {
 /// Enum representing common lexeme types.
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum TokenKind {
-    // Multi-char tokens:
-    /// "// comment"
+    /// A line comment, e.g. `// comment`.
     LineComment { doc_style: Option<DocStyle> },
 
-    /// `/* block comment */`
+    /// A block comment, e.g. `/* block comment */`.
     ///
     /// Block comments can be recursive, so a sequence like `/* /* */`
     /// will not be considered terminated and will result in a parsing error.
@@ -70,18 +69,17 @@ pub enum TokenKind {
     /// Any whitespace character sequence.
     Whitespace,
 
-    /// "ident" or "continue"
-    ///
-    /// At this step, keywords are also considered identifiers.
+    /// An identifier or keyword, e.g. `ident` or `continue`.
     Ident,
 
-    /// Like the above, but containing invalid unicode codepoints.
+    /// An identifier that is invalid because it contains emoji.
     InvalidIdent,
 
-    /// "r#ident"
+    /// A raw identifier, e.g. "r#ident".
     RawIdent,
 
-    /// An unknown prefix, like `foo#`, `foo'`, `foo"`.
+    /// An unknown literal prefix, like `foo#`, `foo'`, `foo"`. Excludes
+    /// literal prefixes that contain emoji, which are considered "invalid".
     ///
     /// Note that only the
     /// prefix (`foo`) is included in the token, not the separator (which is
@@ -93,87 +91,83 @@ pub enum TokenKind {
 
     /// An unknown prefix in a lifetime, like `'foo#`.
     ///
-    /// Note that like above, only the `'` and prefix are included in the token
+    /// Like `UnknownPrefix`, only the `'` and prefix are included in the token
     /// and not the separator.
     UnknownPrefixLifetime,
 
-    /// `'r#lt`, which in edition < 2021 is split into several tokens: `'r # lt`.
+    /// A raw lifetime, e.g. `'r#foo`. In edition < 2021 it will be split into
+    /// several tokens: `'r` and `#` and `foo`.
     RawLifetime,
 
-    /// Similar to the above, but *always* an error on every edition. This is used
-    /// for emoji identifier recovery, as those are not meant to be ever accepted.
-    InvalidPrefix,
-
     /// Guarded string literal prefix: `#"` or `##`.
     ///
     /// Used for reserving "guarded strings" (RFC 3598) in edition 2024.
     /// Split into the component tokens on older editions.
     GuardedStrPrefix,
 
-    /// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
+    /// Literals, e.g. `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
     /// suffix, but may be present here on string and float literals. Users of
     /// this type will need to check for and reject that case.
     ///
     /// See [LiteralKind] for more details.
     Literal { kind: LiteralKind, suffix_start: u32 },
 
-    /// "'a"
+    /// A lifetime, e.g. `'a`.
     Lifetime { starts_with_number: bool },
 
-    // One-char tokens:
-    /// ";"
+    /// `;`
     Semi,
-    /// ","
+    /// `,`
     Comma,
-    /// "."
+    /// `.`
     Dot,
-    /// "("
+    /// `(`
     OpenParen,
-    /// ")"
+    /// `)`
     CloseParen,
-    /// "{"
+    /// `{`
     OpenBrace,
-    /// "}"
+    /// `}`
     CloseBrace,
-    /// "["
+    /// `[`
     OpenBracket,
-    /// "]"
+    /// `]`
     CloseBracket,
-    /// "@"
+    /// `@`
     At,
-    /// "#"
+    /// `#`
     Pound,
-    /// "~"
+    /// `~`
     Tilde,
-    /// "?"
+    /// `?`
     Question,
-    /// ":"
+    /// `:`
     Colon,
-    /// "$"
+    /// `$`
     Dollar,
-    /// "="
+    /// `=`
     Eq,
-    /// "!"
+    /// `!`
     Bang,
-    /// "<"
+    /// `<`
     Lt,
-    /// ">"
+    /// `>`
     Gt,
-    /// "-"
+    /// `-`
     Minus,
-    /// "&"
+    /// `&`
     And,
-    /// "|"
+    /// `|`
     Or,
-    /// "+"
+    /// `+`
     Plus,
-    /// "*"
+    /// `*`
     Star,
-    /// "/"
+    /// `/`
     Slash,
-    /// "^"
+    /// `^`
     Caret,
-    /// "%"
+    /// `%`
     Percent,
 
     /// Unknown token, not expected by the lexer, e.g. "â„–"
@@ -468,7 +462,7 @@ impl Cursor<'_> {
                 Literal { kind, suffix_start }
             }
             // Identifier starting with an emoji. Only lexed for graceful error recovery.
-            c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(),
+            c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
             _ => Unknown,
         };
         let res = Token::new(token_kind, self.pos_within_token());
@@ -552,24 +546,22 @@ impl Cursor<'_> {
         // we see a prefix here, it is definitely an unknown prefix.
         match self.first() {
             '#' | '"' | '\'' => UnknownPrefix,
-            c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(),
+            c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
             _ => Ident,
         }
     }
 
-    fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind {
+    fn invalid_ident(&mut self) -> TokenKind {
         // Start is already eaten, eat the rest of identifier.
         self.eat_while(|c| {
-            unicode_xid::UnicodeXID::is_xid_continue(c)
-                || (!c.is_ascii() && c.is_emoji_char())
-                || c == '\u{200d}'
+            const ZERO_WIDTH_JOINER: char = '\u{200d}';
+            is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER
         });
-        // Known prefixes must have been handled earlier. So if
-        // we see a prefix here, it is definitely an unknown prefix.
-        match self.first() {
-            '#' | '"' | '\'' => InvalidPrefix,
-            _ => InvalidIdent,
-        }
+        // An invalid identifier followed by '#' or '"' or '\'' could be
+        // interpreted as an invalid literal prefix. We don't bother doing that
+        // because the treatment of invalid identifiers and invalid prefixes
+        // would be the same.
+        InvalidIdent
     }
 
     fn c_or_byte_string(
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 6e35d89b488..69fd7f2d8b2 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -772,9 +772,6 @@ lint_suspicious_double_ref_clone =
 lint_suspicious_double_ref_deref =
     using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
 
-lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-    .label = these values have significant drop implementation and will observe changes in drop order under Edition 2024
-
 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 130f3cb7c2a..bda982a3675 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -32,7 +32,7 @@ use rustc_middle::bug;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
 use rustc_session::lint::FutureIncompatibilityReason;
 // hardwired lints from rustc_lint_defs
 pub use rustc_session::lint::builtin::*;
@@ -586,10 +586,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
                 return;
             }
         }
-        if ty.is_copy_modulo_regions(cx.tcx, cx.param_env) {
+        if ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) {
             return;
         }
-        if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.param_env) {
+        if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.typing_env()) {
             return;
         }
         if def.is_variant_list_non_exhaustive()
@@ -637,8 +637,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
 fn type_implements_negative_copy_modulo_regions<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 ) -> bool {
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
     let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
     let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative };
     let obligation = traits::Obligation {
@@ -647,10 +648,7 @@ fn type_implements_negative_copy_modulo_regions<'tcx>(
         recursion_depth: 0,
         predicate: pred.upcast(tcx),
     };
-
-    tcx.infer_ctxt()
-        .build(TypingMode::non_body_analysis())
-        .predicate_must_hold_modulo_regions(&obligation)
+    infcx.predicate_must_hold_modulo_regions(&obligation)
 }
 
 declare_lint! {
@@ -2485,7 +2483,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             });
 
             // Check if this ADT has a constrained layout (like `NonNull` and friends).
-            if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) {
+            if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) {
                 if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
                     &layout.backend_repr
                 {
@@ -2521,7 +2519,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             ty: Ty<'tcx>,
             init: InitKind,
         ) -> Option<InitError> {
-            let ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
+            let ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty);
 
             use rustc_type_ir::TyKind::*;
             match ty.kind() {
@@ -2568,7 +2566,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         let definitely_inhabited = match variant
                             .inhabited_predicate(cx.tcx, *adt_def)
                             .instantiate(cx.tcx, args)
-                            .apply_any_module(cx.tcx, cx.param_env)
+                            .apply_any_module(cx.tcx, cx.typing_env())
                         {
                             // Entirely skip uninhabited variants.
                             Some(false) => return None,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index aa7ec2659d0..6eec32beab0 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -19,7 +19,7 @@ use rustc_middle::bug;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
-use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
 use rustc_session::lint::{
     BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId,
 };
@@ -708,6 +708,10 @@ impl<'tcx> LateContext<'tcx> {
         TypingMode::non_body_analysis()
     }
 
+    pub fn typing_env(&self) -> TypingEnv<'tcx> {
+        TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
+    }
+
     /// Gets the type-checking results for the current body,
     /// or `None` if outside a body.
     pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
@@ -906,7 +910,7 @@ impl<'tcx> LateContext<'tcx> {
             .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
             .and_then(|assoc| {
                 let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
-                tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
+                tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
             })
     }
 
@@ -1010,10 +1014,10 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
     }
 }
 
-impl<'tcx> ty::layout::HasParamEnv<'tcx> for LateContext<'tcx> {
+impl<'tcx> ty::layout::HasTypingEnv<'tcx> for LateContext<'tcx> {
     #[inline]
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env()
     }
 }
 
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index a34c3e26778..e3e51ba263d 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -43,13 +43,10 @@ declare_lint! {
 }
 
 /// FIXME: false negatives (i.e. the lint is not emitted when it should be)
-/// 1. Method calls that are not checked for:
-///    - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
-///    - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
-/// 2. Ways to get a temporary that are not recognized:
+/// 1. Ways to get a temporary that are not recognized:
 ///    - `owning_temporary.field`
 ///    - `owning_temporary[index]`
-/// 3. No checks for ref-to-ptr conversions:
+/// 2. No checks for ref-to-ptr conversions:
 ///    - `&raw [mut] temporary`
 ///    - `&temporary as *(const|mut) _`
 ///    - `ptr::from_ref(&temporary)` and friends
@@ -133,10 +130,11 @@ impl DanglingPointerSearcher<'_, '_> {
 
 fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
-        && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
+        && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+        && cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
         && is_temporary_rvalue(receiver)
         && let ty = cx.typeck_results().expr_ty(receiver)
-        && is_interesting(cx.tcx, ty)
+        && owns_allocation(cx.tcx, ty)
     {
         // FIXME: use `emit_node_lint` when `#[primary_span]` is added.
         cx.tcx.emit_node_span_lint(
@@ -199,24 +197,25 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
     }
 }
 
-// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
-// or any of the above in arbitrary many nested Box'es.
-fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
+// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, UnsafeCell,
+// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es.
+fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
     if ty.is_array() {
         true
     } else if let Some(inner) = ty.boxed_ty() {
         inner.is_slice()
             || inner.is_str()
             || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
-            || is_interesting(tcx, inner)
+            || owns_allocation(tcx, inner)
     } else if let Some(def) = ty.ty_adt_def() {
-        for lang_item in [LangItem::String, LangItem::MaybeUninit] {
+        for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] {
             if tcx.is_lang_item(def.did(), lang_item) {
                 return true;
             }
         }
-        tcx.get_diagnostic_name(def.did())
-            .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
+        tcx.get_diagnostic_name(def.did()).is_some_and(|name| {
+            matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell)
+        })
     } else {
         false
     }
diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs
index 364c6fd488a..8fe86738658 100644
--- a/compiler/rustc_lint/src/drop_forget_useless.rs
+++ b/compiler/rustc_lint/src/drop_forget_useless.rs
@@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
             && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
         {
             let arg_ty = cx.typeck_results().expr_ty(arg);
-            let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
+            let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env());
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
             let let_underscore_ignore_sugg = || {
                 if let Some((_, node)) = cx.tcx.hir().parent_iter(expr.hir_id).nth(0)
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index acccff77a10..4f3184f1d7c 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -68,6 +68,10 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
 }
 
 impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> {
+    fn visit_coroutine_kind(&mut self, coroutine_kind: &'a ast::CoroutineKind) -> Self::Result {
+        self.check_id(coroutine_kind.closure_id());
+    }
+
     fn visit_param(&mut self, param: &'a ast::Param) {
         self.with_lint_attrs(param.id, &param.attrs, |cx| {
             lint_callback!(cx, check_param, param);
@@ -111,17 +115,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         self.with_lint_attrs(e.id, &e.attrs, |cx| {
             lint_callback!(cx, check_expr, e);
             ast_visit::walk_expr(cx, e);
-            // Explicitly check for lints associated with 'closure_id', since
-            // it does not have a corresponding AST node
-            match e.kind {
-                ast::ExprKind::Closure(box ast::Closure {
-                    coroutine_kind: Some(coroutine_kind),
-                    ..
-                }) => {
-                    cx.check_id(coroutine_kind.closure_id());
-                }
-                _ => {}
-            }
             lint_callback!(cx, check_expr_post, e);
         })
     }
@@ -156,14 +149,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         lint_callback!(self, check_fn, fk, span, id);
         self.check_id(id);
         ast_visit::walk_fn(self, fk);
-
-        // Explicitly check for lints associated with 'closure_id', since
-        // it does not have a corresponding AST node
-        if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
-            if let Some(coroutine_kind) = sig.header.coroutine_kind {
-                self.check_id(coroutine_kind.closure_id());
-            }
-        }
     }
 
     fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
@@ -245,15 +230,16 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
     }
 
     fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
-        self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt {
-            ast_visit::AssocCtxt::Trait => {
-                lint_callback!(cx, check_trait_item, item);
-                ast_visit::walk_assoc_item(cx, item, ctxt);
-            }
-            ast_visit::AssocCtxt::Impl => {
-                lint_callback!(cx, check_impl_item, item);
-                ast_visit::walk_assoc_item(cx, item, ctxt);
+        self.with_lint_attrs(item.id, &item.attrs, |cx| {
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item, item);
+                }
+                ast_visit::AssocCtxt::Impl => {
+                    lint_callback!(cx, check_impl_item, item);
+                }
             }
+            ast_visit::walk_assoc_item(cx, item, ctxt);
         });
     }
 
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index cf68e41243f..dbc920ea5ae 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>(
     }
 
     let ty = args.type_at(0);
-    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
+    let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env());
     let ocx = ObligationCtxt::new(&infcx);
 
     let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
@@ -175,7 +175,7 @@ fn suggest_question_mark<'tcx>(
 
     ocx.register_bound(
         cause,
-        cx.param_env,
+        param_env,
         // Erase any region vids from the type, which may not be resolved
         infcx.tcx.erase_regions(ty),
         into_iterator_did,
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 394ea798d3e..45b188205d2 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -131,7 +131,7 @@ impl ClashingExternDeclarations {
         // Check that the declarations match.
         if !structurally_same_type(
             tcx,
-            tcx.param_env(this_fi.owner_id),
+            ty::TypingEnv::non_body_analysis(tcx, this_fi.owner_id),
             existing_decl_ty,
             this_decl_ty,
             types::CItemKind::Declaration,
@@ -205,18 +205,18 @@ fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span {
 /// with the same members (as the declarations shouldn't clash).
 fn structurally_same_type<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     a: Ty<'tcx>,
     b: Ty<'tcx>,
     ckind: types::CItemKind,
 ) -> bool {
     let mut seen_types = UnordSet::default();
-    let result = structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind);
+    let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b, ckind);
     if cfg!(debug_assertions) && result {
         // Sanity-check: must have same ABI, size and alignment.
         // `extern` blocks cannot be generic, so we'll always get a layout here.
-        let a_layout = tcx.layout_of(param_env.and(a)).unwrap();
-        let b_layout = tcx.layout_of(param_env.and(b)).unwrap();
+        let a_layout = tcx.layout_of(typing_env.as_query_input(a)).unwrap();
+        let b_layout = tcx.layout_of(typing_env.as_query_input(b)).unwrap();
         assert_eq!(a_layout.backend_repr, b_layout.backend_repr);
         assert_eq!(a_layout.size, b_layout.size);
         assert_eq!(a_layout.align, b_layout.align);
@@ -227,7 +227,7 @@ fn structurally_same_type<'tcx>(
 fn structurally_same_type_impl<'tcx>(
     seen_types: &mut UnordSet<(Ty<'tcx>, Ty<'tcx>)>,
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     a: Ty<'tcx>,
     b: Ty<'tcx>,
     ckind: types::CItemKind,
@@ -303,7 +303,7 @@ fn structurally_same_type_impl<'tcx>(
                             structurally_same_type_impl(
                                 seen_types,
                                 tcx,
-                                param_env,
+                                typing_env,
                                 tcx.type_of(a_did).instantiate(tcx, a_gen_args),
                                 tcx.type_of(b_did).instantiate(tcx, b_gen_args),
                                 ckind,
@@ -315,23 +315,23 @@ fn structurally_same_type_impl<'tcx>(
                     // For arrays, we also check the length.
                     a_len == b_len
                         && structurally_same_type_impl(
-                            seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
+                            seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
                         )
                 }
                 (Slice(a_ty), Slice(b_ty)) => {
-                    structurally_same_type_impl(seen_types, tcx, param_env, *a_ty, *b_ty, ckind)
+                    structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind)
                 }
                 (RawPtr(a_ty, a_mutbl), RawPtr(b_ty, b_mutbl)) => {
                     a_mutbl == b_mutbl
                         && structurally_same_type_impl(
-                            seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
+                            seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
                         )
                 }
                 (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
                     // For structural sameness, we don't need the region to be same.
                     a_mut == b_mut
                         && structurally_same_type_impl(
-                            seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
+                            seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
                         )
                 }
                 (FnDef(..), FnDef(..)) => {
@@ -346,12 +346,12 @@ fn structurally_same_type_impl<'tcx>(
                     (a_sig.abi, a_sig.safety, a_sig.c_variadic)
                         == (b_sig.abi, b_sig.safety, b_sig.c_variadic)
                         && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
-                            structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind)
+                            structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b, ckind)
                         })
                         && structurally_same_type_impl(
                             seen_types,
                             tcx,
-                            param_env,
+                            typing_env,
                             a_sig.output(),
                             b_sig.output(),
                             ckind,
@@ -379,14 +379,14 @@ fn structurally_same_type_impl<'tcx>(
                 // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
                 // enum layout optimisation is being applied.
                 (Adt(..), _) if is_primitive_or_pointer(b) => {
-                    if let Some(a_inner) = types::repr_nullable_ptr(tcx, param_env, a, ckind) {
+                    if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) {
                         a_inner == b
                     } else {
                         false
                     }
                 }
                 (_, Adt(..)) if is_primitive_or_pointer(a) => {
-                    if let Some(b_inner) = types::repr_nullable_ptr(tcx, param_env, b, ckind) {
+                    if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) {
                         b_inner == a
                     } else {
                         false
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index afcfbebc14b..0e874669043 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -368,7 +368,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
             .cx
             .typeck_results()
             .expr_ty(expr)
-            .has_significant_drop(self.cx.tcx, self.cx.param_env)
+            .has_significant_drop(self.cx.tcx, self.cx.typing_env())
         {
             return ControlFlow::Break(expr.span);
         }
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 036e0381a06..1aacdbd448c 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{
     Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
 };
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::FutureIncompatibilityReason;
@@ -186,8 +186,8 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
             functional_variances.variances
         }),
         outlives_env: LazyCell::new(|| {
-            let param_env = tcx.param_env(parent_def_id);
-            let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
+            let typing_env = ty::TypingEnv::non_body_analysis(tcx, parent_def_id);
+            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
             let ocx = ObligationCtxt::new(&infcx);
             let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
             let implied_bounds =
@@ -262,7 +262,11 @@ where
             // If it's owned by this function
             && let opaque =
                 self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty()
-            && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin
+            // We want to recurse into RPITs and async fns, even though the latter
+            // doesn't overcapture on its own, it may mention additional RPITs
+            // in its bounds.
+            && let hir::OpaqueTyOrigin::FnReturn { parent, .. }
+                | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = opaque.origin
             && parent == self.parent_def_id
         {
             let opaque_span = self.tcx.def_span(opaque_def_id);
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 2f338f42f19..38c38b59bc5 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -103,7 +103,8 @@ declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUE
 impl LateLintPass<'_> for QueryStability {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
-        if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) {
+        if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args)
+        {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
                 cx.emit_span_lint(POTENTIAL_QUERY_INSTABILITY, span, QueryInstability {
@@ -544,7 +545,7 @@ impl Diagnostics {
     ) {
         // Is the callee marked with `#[rustc_lint_diagnostics]`?
         let Some(inst) =
-            ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args).ok().flatten()
+            ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, fn_gen_args).ok().flatten()
         else {
             return;
         };
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index abee9ee7869..9e4e8333164 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
 
             // If the type has a trivial Drop implementation, then it doesn't
             // matter that we drop the value immediately.
-            if !ty.needs_drop(cx.tcx, cx.param_env) {
+            if !ty.needs_drop(cx.tcx, cx.typing_env()) {
                 return;
             }
             // Lint for patterns like `mutex.lock()`, which returns `Result<MutexGuard, _>` as well.
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 97a95787422..4b1dafbdbee 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -123,17 +123,19 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
     let dont_need_to_run: FxIndexSet<LintId> = store
         .get_lints()
         .into_iter()
+        .filter(|lint| {
+            // Lints that show up in future-compat reports must always be run.
+            let has_future_breakage =
+                lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage());
+            !has_future_breakage && !lint.eval_always
+        })
         .filter_map(|lint| {
-            if !lint.eval_always {
-                let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
-                if matches!(lint_level, (Level::Allow, ..))
-                    || (matches!(lint_level, (.., LintLevelSource::Default)))
-                        && lint.default_level(tcx.sess.edition()) == Level::Allow
-                {
-                    Some(LintId::of(lint))
-                } else {
-                    None
-                }
+            let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
+            if matches!(lint_level, (Level::Allow, ..))
+                || (matches!(lint_level, (.., LintLevelSource::Default)))
+                    && lint.default_level(tcx.sess.edition()) == Level::Allow
+            {
+                Some(LintId::of(lint))
             } else {
                 None
             }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 86112277504..4cf5c7b4ff9 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -75,7 +75,6 @@ mod redundant_semicolon;
 mod reference_casting;
 mod shadowed_into_iter;
 mod static_mut_refs;
-mod tail_expr_drop_order;
 mod traits;
 mod types;
 mod unit_bindings;
@@ -116,7 +115,6 @@ use rustc_middle::ty::TyCtxt;
 use shadowed_into_iter::ShadowedIntoIter;
 pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 use static_mut_refs::*;
-use tail_expr_drop_order::TailExprDropOrder;
 use traits::*;
 use types::*;
 use unit_bindings::*;
@@ -240,7 +238,6 @@ late_lint_methods!(
             AsyncFnInTrait: AsyncFnInTrait,
             NonLocalDefinitions: NonLocalDefinitions::default(),
             ImplTraitOvercaptures: ImplTraitOvercaptures,
-            TailExprDropOrder: TailExprDropOrder,
             IfLetRescope: IfLetRescope::default(),
             StaticMutRefs: StaticMutRefs,
             UnqualifiedLocalImports: UnqualifiedLocalImports,
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index cf25ec99e67..36b1ff59c67 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -157,15 +157,17 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String),
             );
 
-            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
+            let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env());
             let suggest_display = is_str
-                || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| {
-                    infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
-                });
+                || cx
+                    .tcx
+                    .get_diagnostic_item(sym::Display)
+                    .is_some_and(|t| infcx.type_implements_trait(t, [ty], param_env).may_apply());
             let suggest_debug = !suggest_display
-                && cx.tcx.get_diagnostic_item(sym::Debug).is_some_and(|t| {
-                    infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
-                });
+                && cx
+                    .tcx
+                    .get_diagnostic_item(sym::Debug)
+                    .is_some_and(|t| infcx.type_implements_trait(t, [ty], param_env).may_apply());
 
             let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
 
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 4890a93fa76..76dc96ae00f 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -94,9 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
 
         let args = cx
             .tcx
-            .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id));
+            .normalize_erasing_regions(cx.typing_env(), cx.typeck_results().node_args(expr.hir_id));
         // Resolve the trait method instance.
-        let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, did, args) else {
+        let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), did, args) else {
             return;
         };
         // (Re)check that it implements the noop diagnostic.
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 45d97403d60..7c6656f91c9 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -168,7 +168,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
         // Except on the presence of non concrete skeleton types (ie generics)
         // since there is no way to make it safe for arbitrary types.
         let inner_ty_has_interior_mutability =
-            !inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton();
+            !inner_ty.is_freeze(cx.tcx, cx.typing_env()) && inner_ty.has_concrete_skeleton();
         (!need_check_freeze || !inner_ty_has_interior_mutability)
             .then_some(inner_ty_has_interior_mutability)
     } else {
diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs
deleted file mode 100644
index 89763059877..00000000000
--- a/compiler/rustc_lint/src/tail_expr_drop_order.rs
+++ /dev/null
@@ -1,305 +0,0 @@
-use std::mem::swap;
-
-use rustc_ast::UnOp;
-use rustc_hir::def::Res;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind};
-use rustc_macros::LintDiagnostic;
-use rustc_middle::ty;
-use rustc_session::lint::FutureIncompatibilityReason;
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::Span;
-use rustc_span::edition::Edition;
-
-use crate::{LateContext, LateLintPass};
-
-declare_lint! {
-    /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
-    /// that runs a custom `Drop` destructor.
-    /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior.
-    /// This lint detects those cases and provides you information on those values and their custom destructor implementations.
-    /// Your discretion on this information is required.
-    ///
-    /// ### Example
-    /// ```rust,edition2021
-    /// #![warn(tail_expr_drop_order)]
-    /// struct Droppy(i32);
-    /// impl Droppy {
-    ///     fn get(&self) -> i32 {
-    ///         self.0
-    ///     }
-    /// }
-    /// impl Drop for Droppy {
-    ///     fn drop(&mut self) {
-    ///         // This is a custom destructor and it induces side-effects that is observable
-    ///         // especially when the drop order at a tail expression changes.
-    ///         println!("loud drop {}", self.0);
-    ///     }
-    /// }
-    /// fn edition_2021() -> i32 {
-    ///     let another_droppy = Droppy(0);
-    ///     Droppy(1).get()
-    /// }
-    /// fn main() {
-    ///     edition_2021();
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// In tail expression of blocks or function bodies,
-    /// values of type with significant `Drop` implementation has an ill-specified drop order
-    /// before Edition 2024 so that they are dropped only after dropping local variables.
-    /// Edition 2024 introduces a new rule with drop orders for them,
-    /// so that they are dropped first before dropping local variables.
-    ///
-    /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary
-    /// implementation of the `Drop` trait on the type, with exceptions including `Vec`,
-    /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise
-    /// so long that the generic types have no significant destructor recursively.
-    /// In other words, a type has a significant drop destructor when it has a `Drop` implementation
-    /// or its destructor invokes a significant destructor on a type.
-    /// Since we cannot completely reason about the change by just inspecting the existence of
-    /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default.
-    ///
-    /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy`
-    /// does in Edition 2024.
-    /// No fix will be proposed by this lint.
-    /// However, the most probable fix is to hoist `Droppy` into its own local variable binding.
-    /// ```rust
-    /// struct Droppy(i32);
-    /// impl Droppy {
-    ///     fn get(&self) -> i32 {
-    ///         self.0
-    ///     }
-    /// }
-    /// fn edition_2024() -> i32 {
-    ///     let value = Droppy(0);
-    ///     let another_droppy = Droppy(1);
-    ///     value.get()
-    /// }
-    /// ```
-    pub TAIL_EXPR_DROP_ORDER,
-    Allow,
-    "Detect and warn on significant change in drop order in tail expression location",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
-        reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>",
-    };
-}
-
-declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]);
-
-impl TailExprDropOrder {
-    fn check_fn_or_closure<'tcx>(
-        cx: &LateContext<'tcx>,
-        fn_kind: hir::intravisit::FnKind<'tcx>,
-        body: &'tcx hir::Body<'tcx>,
-        def_id: rustc_span::def_id::LocalDefId,
-    ) {
-        let mut locals = vec![];
-        if matches!(fn_kind, hir::intravisit::FnKind::Closure) {
-            for &capture in cx.tcx.closure_captures(def_id) {
-                if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue)
-                    && capture.place.ty().has_significant_drop(cx.tcx, cx.param_env)
-                {
-                    locals.push(capture.var_ident.span);
-                }
-            }
-        }
-        for param in body.params {
-            if cx
-                .typeck_results()
-                .node_type(param.hir_id)
-                .has_significant_drop(cx.tcx, cx.param_env)
-            {
-                locals.push(param.span);
-            }
-        }
-        if let hir::ExprKind::Block(block, _) = body.value.kind {
-            LintVisitor { cx, locals }.check_block_inner(block);
-        } else {
-            LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value);
-        }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        fn_kind: hir::intravisit::FnKind<'tcx>,
-        _: &'tcx hir::FnDecl<'tcx>,
-        body: &'tcx hir::Body<'tcx>,
-        _: Span,
-        def_id: rustc_span::def_id::LocalDefId,
-    ) {
-        if !body.value.span.edition().at_least_rust_2024() {
-            Self::check_fn_or_closure(cx, fn_kind, body, def_id);
-        }
-    }
-}
-
-struct LintVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    // We only record locals that have significant drops
-    locals: Vec<Span>,
-}
-
-struct LocalCollector<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    locals: &'a mut Vec<Span>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> {
-    type Result = ();
-    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
-        if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind {
-            let ty = self.cx.typeck_results().node_type(id);
-            if ty.has_significant_drop(self.cx.tcx, self.cx.param_env) {
-                self.locals.push(ident.span);
-            }
-            if let Some(pat) = pat {
-                self.visit_pat(pat);
-            }
-        } else {
-            intravisit::walk_pat(self, pat);
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> {
-    fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
-        let mut locals = <_>::default();
-        swap(&mut locals, &mut self.locals);
-        self.check_block_inner(block);
-        swap(&mut locals, &mut self.locals);
-    }
-    fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
-        LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local);
-    }
-}
-
-impl<'a, 'tcx> LintVisitor<'a, 'tcx> {
-    fn check_block_inner(&mut self, block: &Block<'tcx>) {
-        if block.span.at_least_rust_2024() {
-            // We only lint up to Edition 2021
-            return;
-        }
-        let Some(tail_expr) = block.expr else { return };
-        for stmt in block.stmts {
-            match stmt.kind {
-                StmtKind::Let(let_stmt) => self.visit_local(let_stmt),
-                StmtKind::Item(_) => {}
-                StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e),
-            }
-        }
-        if self.locals.is_empty() {
-            return;
-        }
-        LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true }
-            .visit_expr(tail_expr);
-    }
-}
-
-struct LintTailExpr<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    is_root_tail_expr: bool,
-    locals: &'a [Span],
-}
-
-impl<'a, 'tcx> LintTailExpr<'a, 'tcx> {
-    fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool {
-        loop {
-            match expr.kind {
-                ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access,
-                ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => {
-                    expr = referee
-                }
-                ExprKind::Path(_)
-                    if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind
-                        && let [local, ..] = path.segments
-                        && let Res::Local(_) = local.res =>
-                {
-                    return true;
-                }
-                _ => return false,
-            }
-        }
-    }
-
-    fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool {
-        if Self::expr_eventually_point_into_local(expr) {
-            return false;
-        }
-        self.cx.typeck_results().expr_ty(expr).has_significant_drop(self.cx.tcx, self.cx.param_env)
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> {
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if self.is_root_tail_expr {
-            self.is_root_tail_expr = false;
-        } else if self.expr_generates_nonlocal_droppy_value(expr) {
-            self.cx.tcx.emit_node_span_lint(
-                TAIL_EXPR_DROP_ORDER,
-                expr.hir_id,
-                expr.span,
-                TailExprDropOrderLint { spans: self.locals.to_vec() },
-            );
-            return;
-        }
-        match expr.kind {
-            ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee),
-
-            ExprKind::ConstBlock(_)
-            | ExprKind::Array(_)
-            | ExprKind::Break(_, _)
-            | ExprKind::Continue(_)
-            | ExprKind::Ret(_)
-            | ExprKind::Become(_)
-            | ExprKind::Yield(_, _)
-            | ExprKind::InlineAsm(_)
-            | ExprKind::If(_, _, _)
-            | ExprKind::Loop(_, _, _, _)
-            | ExprKind::Closure(_)
-            | ExprKind::DropTemps(_)
-            | ExprKind::OffsetOf(_, _)
-            | ExprKind::Assign(_, _, _)
-            | ExprKind::AssignOp(_, _, _)
-            | ExprKind::Lit(_)
-            | ExprKind::Err(_) => {}
-
-            ExprKind::MethodCall(_, _, _, _)
-            | ExprKind::Call(_, _)
-            | ExprKind::Type(_, _)
-            | ExprKind::Tup(_)
-            | ExprKind::Binary(_, _, _)
-            | ExprKind::Unary(_, _)
-            | ExprKind::Path(_)
-            | ExprKind::Let(_)
-            | ExprKind::Cast(_, _)
-            | ExprKind::Field(_, _)
-            | ExprKind::Index(_, _, _)
-            | ExprKind::AddrOf(_, _, _)
-            | ExprKind::Struct(_, _, _)
-            | ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr),
-
-            ExprKind::Block(_, _) => {
-                // We do not lint further because the drop order stays the same inside the block
-            }
-        }
-    }
-    fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
-        LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block);
-    }
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_tail_expr_drop_order)]
-struct TailExprDropOrderLint {
-    #[label]
-    pub spans: Vec<Span>,
-}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index be70149b664..b1d7d4ab689 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -292,7 +292,7 @@ fn lint_wide_pointer<'tcx>(
             _ => return None,
         };
 
-        (!ty.is_sized(cx.tcx, cx.param_env))
+        (!ty.is_sized(cx.tcx, cx.typing_env()))
             .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn))))
     };
 
@@ -613,10 +613,11 @@ pub(crate) fn transparent_newtype_field<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
     variant: &'a ty::VariantDef,
 ) -> Option<&'a ty::FieldDef> {
-    let param_env = tcx.param_env(variant.def_id);
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, variant.def_id);
     variant.fields.iter().find(|field| {
         let field_ty = tcx.type_of(field.did).instantiate_identity();
-        let is_1zst = tcx.layout_of(param_env.and(field_ty)).is_ok_and(|layout| layout.is_1zst());
+        let is_1zst =
+            tcx.layout_of(typing_env.as_query_input(field_ty)).is_ok_and(|layout| layout.is_1zst());
         !is_1zst
     })
 }
@@ -624,11 +625,11 @@ pub(crate) fn transparent_newtype_field<'a, 'tcx>(
 /// Is type known to be non-null?
 fn ty_is_known_nonnull<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
     mode: CItemKind,
 ) -> bool {
-    let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+    let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
 
     match ty.kind() {
         ty::FnPtr(..) => true,
@@ -649,7 +650,7 @@ fn ty_is_known_nonnull<'tcx>(
             def.variants()
                 .iter()
                 .filter_map(|variant| transparent_newtype_field(tcx, variant))
-                .any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode))
+                .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode))
         }
         _ => false,
     }
@@ -659,10 +660,10 @@ fn ty_is_known_nonnull<'tcx>(
 /// If the type passed in was not scalar, returns None.
 fn get_nullable_type<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ty<'tcx>> {
-    let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+    let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
 
     Some(match *ty.kind() {
         ty::Adt(field_def, field_args) => {
@@ -679,7 +680,7 @@ fn get_nullable_type<'tcx>(
                     .expect("No non-zst fields in transparent type.")
                     .ty(tcx, field_args)
             };
-            return get_nullable_type(tcx, param_env, inner_field_ty);
+            return get_nullable_type(tcx, typing_env, inner_field_ty);
         }
         ty::Int(ty) => Ty::new_int(tcx, ty),
         ty::Uint(ty) => Ty::new_uint(tcx, ty),
@@ -708,10 +709,10 @@ fn get_nullable_type<'tcx>(
 /// - Does not have the `#[non_exhaustive]` attribute.
 fn is_niche_optimization_candidate<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> bool {
-    if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
+    if tcx.layout_of(typing_env.as_query_input(ty)).is_ok_and(|layout| !layout.is_1zst()) {
         return false;
     }
 
@@ -734,7 +735,7 @@ fn is_niche_optimization_candidate<'tcx>(
 /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
 pub(crate) fn repr_nullable_ptr<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
     ckind: CItemKind,
 ) -> Option<Ty<'tcx>> {
@@ -747,9 +748,9 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
                     let ty1 = field1.ty(tcx, args);
                     let ty2 = field2.ty(tcx, args);
 
-                    if is_niche_optimization_candidate(tcx, param_env, ty1) {
+                    if is_niche_optimization_candidate(tcx, typing_env, ty1) {
                         ty2
-                    } else if is_niche_optimization_candidate(tcx, param_env, ty2) {
+                    } else if is_niche_optimization_candidate(tcx, typing_env, ty2) {
                         ty1
                     } else {
                         return None;
@@ -760,20 +761,20 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
             _ => return None,
         };
 
-        if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) {
+        if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) {
             return None;
         }
 
         // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
         // If the computed size for the field and the enum are different, the nonnull optimization isn't
         // being applied (and we've got a problem somewhere).
-        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).ok();
+        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok();
         if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) {
             bug!("improper_ctypes: Option nonnull optimization not applied?");
         }
 
         // Return the nullable type this Option-like enum can be safely represented with.
-        let field_ty_layout = tcx.layout_of(param_env.and(field_ty));
+        let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty));
         if field_ty_layout.is_err() && !field_ty.has_non_region_param() {
             bug!("should be able to compute the layout of non-polymorphic type");
         }
@@ -784,10 +785,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
                 WrappingRange { start: 0, end }
                     if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 =>
                 {
-                    return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
+                    return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap());
                 }
                 WrappingRange { start: 1, .. } => {
-                    return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
+                    return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap());
                 }
                 WrappingRange { start, end } => {
                     unreachable!("Unhandled start and end range: ({}, {})", start, end)
@@ -825,7 +826,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         let field_ty = self
             .cx
             .tcx
-            .try_normalize_erasing_regions(self.cx.param_env, field_ty)
+            .try_normalize_erasing_regions(self.cx.typing_env(), field_ty)
             .unwrap_or(field_ty);
         self.check_type_for_ffi(acc, field_ty)
     }
@@ -903,7 +904,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 if let Some(boxed) = ty.boxed_ty()
                     && matches!(self.mode, CItemKind::Definition)
                 {
-                    if boxed.is_sized(tcx, self.cx.param_env) {
+                    if boxed.is_sized(tcx, self.cx.typing_env()) {
                         return FfiSafe;
                     } else {
                         return FfiUnsafe {
@@ -988,7 +989,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         {
                             // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
                             if let Some(ty) =
-                                repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
+                                repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty, self.mode)
                             {
                                 return self.check_type_for_ffi(acc, ty);
                             }
@@ -1068,7 +1069,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
                 if {
                     matches!(self.mode, CItemKind::Definition)
-                        && ty.is_sized(self.cx.tcx, self.cx.param_env)
+                        && ty.is_sized(self.cx.tcx, self.cx.typing_env())
                 } =>
             {
                 FfiSafe
@@ -1196,7 +1197,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         if let Some(ty) = self
             .cx
             .tcx
-            .try_normalize_erasing_regions(self.cx.param_env, ty)
+            .try_normalize_erasing_regions(self.cx.typing_env(), ty)
             .unwrap_or(ty)
             .visit_with(&mut ProhibitOpaqueTypes)
             .break_value()
@@ -1220,7 +1221,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             return;
         }
 
-        let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.param_env, ty).unwrap_or(ty);
+        let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
 
         // C doesn't really support passing arrays by value - the only way to pass an array by value
         // is through a struct. So, first test that the top level isn't an array, and then
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index b50a95e7d2b..5ec920d39f4 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -272,7 +272,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 || !ty.is_inhabited_from(
                     cx.tcx,
                     cx.tcx.parent_module(expr.hir_id).to_def_id(),
-                    cx.param_env,
+                    cx.typing_env(),
                 )
             {
                 return Some(MustUsePath::Suppressed);
@@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
         if let hir::StmtKind::Semi(expr) = s.kind {
             if let hir::ExprKind::Path(_) = expr.kind {
                 let ty = cx.typeck_results().expr_ty(expr);
-                if ty.needs_drop(cx.tcx, cx.param_env) {
+                if ty.needs_drop(cx.tcx, cx.typing_env()) {
                     let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span)
                     {
                         PathStatementDropSub::Suggestion { span: s.span, snippet }
@@ -584,6 +584,7 @@ enum UnusedDelimsCtx {
     MatchScrutineeExpr,
     ReturnValue,
     BlockRetValue,
+    BreakValue,
     LetScrutineeExpr,
     ArrayLenExpr,
     AnonConst,
@@ -605,6 +606,7 @@ impl From<UnusedDelimsCtx> for &'static str {
             UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
             UnusedDelimsCtx::ReturnValue => "`return` value",
             UnusedDelimsCtx::BlockRetValue => "block return value",
+            UnusedDelimsCtx::BreakValue => "`break` value",
             UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
             UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
             UnusedDelimsCtx::MatchArmExpr => "match arm expression",
@@ -913,6 +915,10 @@ trait UnusedDelimLint {
                 (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
             }
 
+            Break(_, Some(ref value)) => {
+                (value, UnusedDelimsCtx::BreakValue, false, None, None, true)
+            }
+
             Index(_, ref value, _) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
 
             Assign(_, ref value, _) | AssignOp(.., ref value) => {
@@ -1063,6 +1069,9 @@ impl UnusedDelimLint for UnusedParens {
                                 _,
                                 _,
                             ) if node.is_lazy()))
+                    && !((ctx == UnusedDelimsCtx::ReturnValue
+                        || ctx == UnusedDelimsCtx::BreakValue)
+                        && matches!(inner.kind, ast::ExprKind::Assign(_, _, _)))
                 {
                     self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
                 }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 51146cfd2e9..9036741e078 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -101,6 +101,7 @@ declare_lint_pass! {
         SINGLE_USE_LIFETIMES,
         SOFT_UNSTABLE,
         STABLE_FEATURES,
+        TAIL_EXPR_DROP_ORDER,
         TEST_UNSTABLE_LINT,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
         TRIVIAL_CASTS,
@@ -3185,6 +3186,7 @@ declare_lint! {
     pub UNEXPECTED_CFGS,
     Warn,
     "detects unexpected names and values in `#[cfg]` conditions",
+    report_in_external_macro
 }
 
 declare_lint! {
@@ -4185,7 +4187,7 @@ declare_lint! {
     Warn,
     "never type fallback affecting unsafe function calls",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
+        reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024),
         reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
     };
     @edition Edition2024 => Deny;
@@ -4239,7 +4241,7 @@ declare_lint! {
     Warn,
     "never type fallback affecting unsafe function calls",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
+        reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024),
         reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
     };
     report_in_external_macro
@@ -4994,6 +4996,83 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
+    /// that runs a custom `Drop` destructor.
+    /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior.
+    /// This lint detects those cases and provides you information on those values and their custom destructor implementations.
+    /// Your discretion on this information is required.
+    ///
+    /// ### Example
+    /// ```rust,edition2021
+    /// #![warn(tail_expr_drop_order)]
+    /// struct Droppy(i32);
+    /// impl Droppy {
+    ///     fn get(&self) -> i32 {
+    ///         self.0
+    ///     }
+    /// }
+    /// impl Drop for Droppy {
+    ///     fn drop(&mut self) {
+    ///         // This is a custom destructor and it induces side-effects that is observable
+    ///         // especially when the drop order at a tail expression changes.
+    ///         println!("loud drop {}", self.0);
+    ///     }
+    /// }
+    /// fn edition_2021() -> i32 {
+    ///     let another_droppy = Droppy(0);
+    ///     Droppy(1).get()
+    /// }
+    /// fn main() {
+    ///     edition_2021();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In tail expression of blocks or function bodies,
+    /// values of type with significant `Drop` implementation has an ill-specified drop order
+    /// before Edition 2024 so that they are dropped only after dropping local variables.
+    /// Edition 2024 introduces a new rule with drop orders for them,
+    /// so that they are dropped first before dropping local variables.
+    ///
+    /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary
+    /// implementation of the `Drop` trait on the type, with exceptions including `Vec`,
+    /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise
+    /// so long that the generic types have no significant destructor recursively.
+    /// In other words, a type has a significant drop destructor when it has a `Drop` implementation
+    /// or its destructor invokes a significant destructor on a type.
+    /// Since we cannot completely reason about the change by just inspecting the existence of
+    /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default.
+    ///
+    /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy`
+    /// does in Edition 2024.
+    /// No fix will be proposed by this lint.
+    /// However, the most probable fix is to hoist `Droppy` into its own local variable binding.
+    /// ```rust
+    /// struct Droppy(i32);
+    /// impl Droppy {
+    ///     fn get(&self) -> i32 {
+    ///         self.0
+    ///     }
+    /// }
+    /// fn edition_2024() -> i32 {
+    ///     let value = Droppy(0);
+    ///     let another_droppy = Droppy(1);
+    ///     value.get()
+    /// }
+    /// ```
+    pub TAIL_EXPR_DROP_ORDER,
+    Allow,
+    "Detect and warn on significant change in drop order in tail expression location",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+        reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>",
+    };
+}
+
+declare_lint! {
     /// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens
     /// that will be parsed as part of a guarded string literal in Rust 2024.
     ///
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 0caf6ef3a6d..c74fceeedba 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -381,6 +381,8 @@ pub enum FutureIncompatibilityReason {
     /// hard errors (and the lint removed). Preferably when there is some
     /// confidence that the number of impacted projects is very small (few
     /// should have a broken dependency in their dependency tree).
+    ///
+    /// [`EditionAndFutureReleaseError`]: FutureIncompatibilityReason::EditionAndFutureReleaseError
     FutureReleaseErrorReportInDeps,
     /// Code that changes meaning in some way in a
     /// future release.
@@ -419,6 +421,28 @@ pub enum FutureIncompatibilityReason {
     /// slightly changes the text of the diagnostic, but is otherwise the
     /// same.
     EditionSemanticsChange(Edition),
+    /// This will be an error in the provided edition *and* in a future
+    /// release.
+    ///
+    /// This variant a combination of [`FutureReleaseErrorDontReportInDeps`]
+    /// and [`EditionError`]. This is useful in rare cases when we
+    /// want to have "preview" of a breaking change in an edition, but do a
+    /// breaking change later on all editions anyway.
+    ///
+    /// [`EditionError`]: FutureIncompatibilityReason::EditionError
+    /// [`FutureReleaseErrorDontReportInDeps`]: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
+    EditionAndFutureReleaseError(Edition),
+    /// This will change meaning in the provided edition *and* in a future
+    /// release.
+    ///
+    /// This variant a combination of [`FutureReleaseSemanticsChange`]
+    /// and [`EditionSemanticsChange`]. This is useful in rare cases when we
+    /// want to have "preview" of a breaking change in an edition, but do a
+    /// breaking change later on all editions anyway.
+    ///
+    /// [`EditionSemanticsChange`]: FutureIncompatibilityReason::EditionSemanticsChange
+    /// [`FutureReleaseSemanticsChange`]: FutureIncompatibilityReason::FutureReleaseSemanticsChange
+    EditionAndFutureReleaseSemanticsChange(Edition),
     /// A custom reason.
     ///
     /// Choose this variant if the built-in text of the diagnostic of the
@@ -431,9 +455,29 @@ pub enum FutureIncompatibilityReason {
 impl FutureIncompatibilityReason {
     pub fn edition(self) -> Option<Edition> {
         match self {
-            Self::EditionError(e) => Some(e),
-            Self::EditionSemanticsChange(e) => Some(e),
-            _ => None,
+            Self::EditionError(e)
+            | Self::EditionSemanticsChange(e)
+            | Self::EditionAndFutureReleaseError(e)
+            | Self::EditionAndFutureReleaseSemanticsChange(e) => Some(e),
+
+            FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
+            | FutureIncompatibilityReason::FutureReleaseErrorReportInDeps
+            | FutureIncompatibilityReason::FutureReleaseSemanticsChange
+            | FutureIncompatibilityReason::Custom(_) => None,
+        }
+    }
+
+    pub fn has_future_breakage(self) -> bool {
+        match self {
+            FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => true,
+
+            FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
+            | FutureIncompatibilityReason::FutureReleaseSemanticsChange
+            | FutureIncompatibilityReason::EditionError(_)
+            | FutureIncompatibilityReason::EditionSemanticsChange(_)
+            | FutureIncompatibilityReason::EditionAndFutureReleaseError(_)
+            | FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(_)
+            | FutureIncompatibilityReason::Custom(_) => false,
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 493db498b7c..ace46891f83 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -6,7 +6,7 @@ use rustc_ast::CRATE_NODE_ID;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::query::LocalCrate;
-use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{self, List, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{
@@ -613,7 +613,7 @@ impl<'tcx> Collector<'tcx> {
             .map(|ty| {
                 let layout = self
                     .tcx
-                    .layout_of(ParamEnvAnd { param_env: ParamEnv::empty(), value: ty })
+                    .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                     .expect("layout")
                     .layout;
                 // In both stdcall and fastcall, we always round up the argument size to the
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 045fd0565ba..a89096beb8c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -275,7 +275,7 @@ provide! { tcx, def_id, other, cdata,
     defaultness => { table_direct }
     constness => { table_direct }
     const_conditions => { table }
-    implied_const_bounds => { table_defaulted_array }
+    explicit_implied_const_bounds => { table_defaulted_array }
     coerce_unsized_info => {
         Ok(cdata
             .root
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index b5391247cea..8378e7c6e9b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1463,8 +1463,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record_array!(self.tables.module_children_non_reexports[def_id] <-
                     module_children.iter().map(|child| child.res.def_id().index));
                 if self.tcx.is_const_trait(def_id) {
-                    record_defaulted_array!(self.tables.implied_const_bounds[def_id]
-                        <- self.tcx.implied_const_bounds(def_id).skip_binder());
+                    record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                        <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
                 }
             }
             if let DefKind::TraitAlias = def_kind {
@@ -1532,6 +1532,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.encode_explicit_item_super_predicates(def_id);
                 record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id));
                 self.encode_precise_capturing_args(def_id);
+                if tcx.is_conditionally_const(def_id) {
+                    record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                        <- tcx.explicit_implied_const_bounds(def_id).skip_binder());
+                }
             }
             if tcx.impl_method_has_trait_impl_trait_tys(def_id)
                 && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
@@ -1654,8 +1658,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     self.encode_explicit_item_bounds(def_id);
                     self.encode_explicit_item_super_predicates(def_id);
                     if tcx.is_conditionally_const(def_id) {
-                        record_defaulted_array!(self.tables.implied_const_bounds[def_id]
-                            <- self.tcx.implied_const_bounds(def_id).skip_binder());
+                        record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                            <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
                     }
                 }
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 58f58efb116..4a8f8521b4f 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -391,7 +391,7 @@ define_tables! {
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
-    implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>,
+    explicit_implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
     opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index b5862565e8e..971d036fa69 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -290,12 +290,7 @@ pub fn lint_level(
         let has_future_breakage = future_incompatible.map_or(
             // Default allow lints trigger too often for testing.
             sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
-            |incompat| {
-                matches!(
-                    incompat.reason,
-                    FutureIncompatibilityReason::FutureReleaseErrorReportInDeps
-                )
-            },
+            |incompat| incompat.reason.has_future_breakage(),
         );
 
         // Convert lint level to error level.
@@ -382,6 +377,17 @@ pub fn lint_level(
                 FutureIncompatibilityReason::EditionSemanticsChange(edition) => {
                     format!("this changes meaning in Rust {edition}")
                 }
+                FutureIncompatibilityReason::EditionAndFutureReleaseError(edition) => {
+                    format!(
+                        "this was previously accepted by the compiler but is being phased out; \
+                         it will become a hard error in Rust {edition} and in a future release in all editions!"
+                    )
+                }
+                FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(edition) => {
+                    format!(
+                        "this changes meaning in Rust {edition} and in a future release in all editions!"
+                    )
+                }
                 FutureIncompatibilityReason::Custom(reason) => reason.to_owned(),
             };
 
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 4e44de33611..114211b27c1 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -236,6 +236,11 @@ pub struct ScopeTree {
     /// during type check based on a traversal of the AST.
     pub rvalue_candidates: HirIdMap<RvalueCandidateType>,
 
+    /// Backwards incompatible scoping that will be introduced in future editions.
+    /// This information is used later for linting to identify locals and
+    /// temporary values that will receive backwards-incompatible drop orders.
+    pub backwards_incompatible_scope: UnordMap<hir::ItemLocalId, Scope>,
+
     /// If there are any `yield` nested within a scope, this map
     /// stores the `Span` of the last one and its index in the
     /// postorder of the Visitor traversal on the HIR.
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index e6b36299d7f..94d13021612 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -10,7 +10,6 @@ use rustc_attr::{
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee};
 use rustc_feature::GateIssue;
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
 use rustc_hir::{self as hir, HirId};
 use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic};
@@ -24,7 +23,7 @@ use rustc_span::symbol::{Symbol, sym};
 use tracing::debug;
 
 pub use self::StabilityLevel::*;
-use crate::ty::{self, TyCtxt};
+use crate::ty::TyCtxt;
 
 #[derive(PartialEq, Clone, Copy, Debug)]
 pub enum StabilityLevel {
@@ -273,22 +272,6 @@ pub enum EvalResult {
     Unmarked,
 }
 
-// See issue #38412.
-fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    if tcx.def_kind(def_id) == DefKind::TyParam {
-        // Have no visibility, considered public for the purpose of this check.
-        return false;
-    }
-    match tcx.visibility(def_id) {
-        // Must check stability for `pub` items.
-        ty::Visibility::Public => false,
-
-        // These are not visible outside crate; therefore
-        // stability markers are irrelevant, if even present.
-        ty::Visibility::Restricted(..) => true,
-    }
-}
-
 // See issue #83250.
 fn suggestion_for_allocator_api(
     tcx: TyCtxt<'_>,
@@ -407,11 +390,6 @@ impl<'tcx> TyCtxt<'tcx> {
             def_id, span, stability
         );
 
-        // Issue #38412: private items lack stability markers.
-        if skip_stability_check_due_to_privacy(self, def_id) {
-            return EvalResult::Allow;
-        }
-
         match stability {
             Some(Stability {
                 level: attr::Unstable { reason, issue, is_soft, implied_by },
@@ -495,11 +473,6 @@ impl<'tcx> TyCtxt<'tcx> {
             "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
         );
 
-        // Issue #38412: private items lack stability markers.
-        if skip_stability_check_due_to_privacy(self, def_id) {
-            return EvalResult::Allow;
-        }
-
         match stability {
             Some(DefaultBodyStability {
                 level: attr::Unstable { reason, issue, is_soft, .. },
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index f95635370dc..a51370369b8 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -102,10 +102,11 @@ impl<'tcx> ConstValue<'tcx> {
     pub fn try_to_bits_for_ty(
         &self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ty: Ty<'tcx>,
     ) -> Option<u128> {
-        let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+        let size =
+            tcx.layout_of(typing_env.with_reveal_all_normalized(tcx).as_query_input(ty)).ok()?.size;
         self.try_to_bits(size)
     }
 
@@ -314,7 +315,7 @@ impl<'tcx> Const<'tcx> {
     pub fn eval(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         span: Span,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
         match self {
@@ -333,7 +334,7 @@ impl<'tcx> Const<'tcx> {
             }
             Const::Unevaluated(uneval, _) => {
                 // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
-                tcx.const_eval_resolve(param_env, uneval, span)
+                tcx.const_eval_resolve(typing_env, uneval, span)
             }
             Const::Val(val, _) => Ok(val),
         }
@@ -343,7 +344,7 @@ impl<'tcx> Const<'tcx> {
     pub fn try_eval_scalar(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<Scalar> {
         if let Const::Ty(_, c) = self
             && let ty::ConstKind::Value(ty, val) = c.kind()
@@ -354,7 +355,7 @@ impl<'tcx> Const<'tcx> {
             // pointer here, which valtrees don't represent.)
             Some(val.unwrap_leaf().into())
         } else {
-            self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar()
+            self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar()
         }
     }
 
@@ -362,23 +363,29 @@ impl<'tcx> Const<'tcx> {
     pub fn try_eval_scalar_int(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<ScalarInt> {
-        self.try_eval_scalar(tcx, param_env)?.try_to_scalar_int().ok()
+        self.try_eval_scalar(tcx, typing_env)?.try_to_scalar_int().ok()
     }
 
     #[inline]
-    pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> {
-        let int = self.try_eval_scalar_int(tcx, param_env)?;
-        let size =
-            tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
+    pub fn try_eval_bits(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+    ) -> Option<u128> {
+        let int = self.try_eval_scalar_int(tcx, typing_env)?;
+        let size = tcx
+            .layout_of(typing_env.with_reveal_all_normalized(tcx).as_query_input(self.ty()))
+            .ok()?
+            .size;
         Some(int.to_bits(size))
     }
 
     /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
     #[inline]
-    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
-        self.try_eval_bits(tcx, param_env)
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, typing_env)
             .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
     }
 
@@ -386,21 +393,21 @@ impl<'tcx> Const<'tcx> {
     pub fn try_eval_target_usize(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<u64> {
-        Some(self.try_eval_scalar_int(tcx, param_env)?.to_target_usize(tcx))
+        Some(self.try_eval_scalar_int(tcx, typing_env)?.to_target_usize(tcx))
     }
 
     #[inline]
     /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
-    pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u64 {
-        self.try_eval_target_usize(tcx, param_env)
+    pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u64 {
+        self.try_eval_target_usize(tcx, typing_env)
             .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
     }
 
     #[inline]
-    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
-        self.try_eval_scalar_int(tcx, param_env)?.try_into().ok()
+    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<bool> {
+        self.try_eval_scalar_int(tcx, typing_env)?.try_into().ok()
     }
 
     #[inline]
@@ -411,17 +418,16 @@ impl<'tcx> Const<'tcx> {
     pub fn from_bits(
         tcx: TyCtxt<'tcx>,
         bits: u128,
-        param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+        typing_env: ty::TypingEnv<'tcx>,
+        ty: Ty<'tcx>,
     ) -> Self {
         let size = tcx
-            .layout_of(param_env_ty)
-            .unwrap_or_else(|e| {
-                bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
-            })
+            .layout_of(typing_env.as_query_input(ty))
+            .unwrap_or_else(|e| bug!("could not compute layout for {ty:?}: {e:?}"))
             .size;
         let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
 
-        Self::Val(cv, param_env_ty.value)
+        Self::Val(cv, ty)
     }
 
     #[inline]
@@ -438,7 +444,8 @@ impl<'tcx> Const<'tcx> {
 
     pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
         let ty = tcx.types.usize;
-        Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
+        let typing_env = ty::TypingEnv::fully_monomorphized();
+        Self::from_bits(tcx, n as u128, typing_env, ty)
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 8ec7e1851a5..08afa33c6b4 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -59,22 +59,33 @@ impl ErrorHandled {
 pub struct ReportedErrorInfo {
     error: ErrorGuaranteed,
     is_tainted_by_errors: bool,
+    /// Whether this is the kind of error that can sometimes occur, and sometimes not.
+    /// Used for resource exhaustion errors.
+    can_be_spurious: bool,
 }
 
 impl ReportedErrorInfo {
     #[inline]
     pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
-        ReportedErrorInfo { is_tainted_by_errors: true, error }
+        ReportedErrorInfo { is_tainted_by_errors: true, can_be_spurious: false, error }
     }
+    #[inline]
+    pub fn spurious(error: ErrorGuaranteed) -> ReportedErrorInfo {
+        ReportedErrorInfo { can_be_spurious: true, is_tainted_by_errors: false, error }
+    }
+
     pub fn is_tainted_by_errors(&self) -> bool {
         self.is_tainted_by_errors
     }
+    pub fn can_be_spurious(&self) -> bool {
+        self.can_be_spurious
+    }
 }
 
 impl From<ErrorGuaranteed> for ReportedErrorInfo {
     #[inline]
     fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
-        ReportedErrorInfo { is_tainted_by_errors: false, error }
+        ReportedErrorInfo { is_tainted_by_errors: false, can_be_spurious: false, error }
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index f225ad94aa7..8d73c9e76de 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -46,7 +46,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
 pub use self::value::Scalar;
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
+use crate::ty::{self, Instance, Ty, TyCtxt};
 
 /// Uniquely identifies one of the following:
 /// - A constant
@@ -312,7 +312,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
         }
     }
 
-    pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability {
+    pub fn mutability(&self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Mutability {
         // Let's see what kind of memory we are.
         match self {
             GlobalAlloc::Static(did) => {
@@ -334,7 +334,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
                                 .type_of(did)
                                 .no_bound_vars()
                                 .expect("statics should not have generic parameters")
-                                .is_freeze(tcx, param_env) =>
+                                .is_freeze(tcx, typing_env) =>
                         {
                             Mutability::Mut
                         }
@@ -351,7 +351,11 @@ impl<'tcx> GlobalAlloc<'tcx> {
         }
     }
 
-    pub fn size_and_align(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> (Size, Align) {
+    pub fn size_and_align(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+    ) -> (Size, Align) {
         match self {
             GlobalAlloc::Static(def_id) => {
                 let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else {
@@ -374,7 +378,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
                         .type_of(def_id)
                         .no_bound_vars()
                         .expect("statics should not have generic parameters");
-                    let layout = tcx.layout_of(param_env.and(ty)).unwrap();
+                    let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
                     assert!(layout.is_sized());
                     (layout.size, layout.align.abi)
                 }
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 2ecf1d0bcf8..6eeafe18b35 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -25,8 +25,8 @@ impl<'tcx> TyCtxt<'tcx> {
         let args = GenericArgs::identity_for_item(self, def_id);
         let instance = ty::Instance::new(def_id, args);
         let cid = GlobalId { instance, promoted: None };
-        let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
-        self.const_eval_global_id(param_env, cid, DUMMY_SP)
+        let typing_env = ty::TypingEnv::post_analysis(self, def_id);
+        self.const_eval_global_id(typing_env, cid, DUMMY_SP)
     }
 
     /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
@@ -41,8 +41,8 @@ impl<'tcx> TyCtxt<'tcx> {
         let args = GenericArgs::identity_for_item(self, def_id);
         let instance = ty::Instance::new(def_id, args);
         let cid = GlobalId { instance, promoted: None };
-        let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
-        let inputs = self.erase_regions(param_env.and(cid));
+        let typing_env = ty::TypingEnv::post_analysis(self, def_id);
+        let inputs = self.erase_regions(typing_env.as_query_input(cid));
         self.eval_to_allocation_raw(inputs)
     }
 
@@ -58,7 +58,7 @@ impl<'tcx> TyCtxt<'tcx> {
     #[instrument(level = "debug", skip(self))]
     pub fn const_eval_resolve(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ct: mir::UnevaluatedConst<'tcx>,
         span: Span,
     ) -> EvalToConstValueResult<'tcx> {
@@ -72,14 +72,11 @@ impl<'tcx> TyCtxt<'tcx> {
             bug!("did not expect inference variables here");
         }
 
-        match ty::Instance::try_resolve(
-            self, param_env,
-            // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
-            ct.def, ct.args,
-        ) {
+        // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
+        match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: ct.promoted };
-                self.const_eval_global_id(param_env, cid, span)
+                self.const_eval_global_id(typing_env, cid, span)
             }
             // For errors during resolution, we deliberately do not point at the usage site of the constant,
             // since for these errors the place the constant is used shouldn't matter.
@@ -91,7 +88,7 @@ impl<'tcx> TyCtxt<'tcx> {
     #[instrument(level = "debug", skip(self))]
     pub fn const_eval_resolve_for_typeck(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ct: ty::UnevaluatedConst<'tcx>,
         span: Span,
     ) -> EvalToValTreeResult<'tcx> {
@@ -105,10 +102,10 @@ impl<'tcx> TyCtxt<'tcx> {
             bug!("did not expect inference variables here");
         }
 
-        match ty::Instance::try_resolve(self, param_env, ct.def, ct.args) {
+        match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: None };
-                self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
+                self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| {
                     // We are emitting the lint here instead of in `is_const_evaluatable`
                     // as we normalize obligations before checking them, and normalization
                     // uses this function to evaluate this constant.
@@ -147,24 +144,25 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn const_eval_instance(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         instance: ty::Instance<'tcx>,
         span: Span,
     ) -> EvalToConstValueResult<'tcx> {
-        self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
+        self.const_eval_global_id(typing_env, GlobalId { instance, promoted: None }, span)
     }
 
     /// Evaluate a constant to a `ConstValue`.
     #[instrument(skip(self), level = "debug")]
     pub fn const_eval_global_id(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         cid: GlobalId<'tcx>,
         span: Span,
     ) -> EvalToConstValueResult<'tcx> {
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
-        let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid));
+        let inputs =
+            self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid));
         if !span.is_dummy() {
             // The query doesn't know where it is being invoked, so we need to fix the span.
             self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
@@ -177,13 +175,14 @@ impl<'tcx> TyCtxt<'tcx> {
     #[instrument(skip(self), level = "debug")]
     pub fn const_eval_global_id_for_typeck(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         cid: GlobalId<'tcx>,
         span: Span,
     ) -> EvalToValTreeResult<'tcx> {
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
-        let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid));
+        let inputs =
+            self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid));
         debug!(?inputs);
         if !span.is_dummy() {
             // The query doesn't know where it is being invoked, so we need to fix the span.
@@ -205,12 +204,12 @@ impl<'tcx> TyCtxtEnsure<'tcx> {
         // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
         // encountered.
         let args = GenericArgs::identity_for_item(self.tcx, def_id);
-        let instance = ty::Instance::new(def_id, args);
+        let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args));
         let cid = GlobalId { instance, promoted: None };
-        let param_env = self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx);
+        let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id);
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
-        let inputs = self.tcx.erase_regions(param_env.and(cid));
+        let inputs = self.tcx.erase_regions(typing_env.as_query_input(cid));
         self.eval_to_const_value_raw(inputs)
     }
 }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 260c6543f98..e2379f282ec 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -39,7 +39,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{
-    self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingMode,
+    self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv,
     UserTypeAnnotationIndex,
 };
 
@@ -452,12 +452,14 @@ impl<'tcx> Body<'tcx> {
         self.basic_blocks.as_mut()
     }
 
-    pub fn typing_mode(&self, _tcx: TyCtxt<'tcx>) -> TypingMode<'tcx> {
+    pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
         match self.phase {
-            // FIXME(#132279): the MIR is quite clearly inside of a body, so we
-            // should instead reveal opaques defined by that body here.
-            MirPhase::Built | MirPhase::Analysis(_) => TypingMode::non_body_analysis(),
-            MirPhase::Runtime(_) => TypingMode::PostAnalysis,
+            // FIXME(#132279): we should reveal the opaques defined in the body during analysis.
+            MirPhase::Built | MirPhase::Analysis(_) => TypingEnv {
+                typing_mode: ty::TypingMode::non_body_analysis(),
+                param_env: tcx.param_env(self.source.def_id()),
+            },
+            MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()),
         }
     }
 
@@ -618,7 +620,7 @@ impl<'tcx> Body<'tcx> {
     }
 
     /// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the
-    /// dimscriminant in monomorphization, we return the discriminant bits and the
+    /// discriminant in monomorphization, we return the discriminant bits and the
     /// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator.
     fn try_const_mono_switchint<'a>(
         tcx: TyCtxt<'tcx>,
@@ -627,13 +629,15 @@ impl<'tcx> Body<'tcx> {
     ) -> Option<(u128, &'a SwitchTargets)> {
         // There are two places here we need to evaluate a constant.
         let eval_mono_const = |constant: &ConstOperand<'tcx>| {
-            let env = ty::ParamEnv::reveal_all();
+            // FIXME(#132279): what is this, why are we using an empty environment with
+            // `RevealAll` here.
+            let typing_env = ty::TypingEnv::fully_monomorphized();
             let mono_literal = instance.instantiate_mir_and_normalize_erasing_regions(
                 tcx,
-                env,
+                typing_env,
                 crate::ty::EarlyBinder::bind(constant.const_),
             );
-            mono_literal.try_eval_bits(tcx, env)
+            mono_literal.try_eval_bits(tcx, typing_env)
         };
 
         let TerminatorKind::SwitchInt { discr, targets } = &block.terminator().kind else {
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index d8d99deeb2c..244d22d082f 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -46,7 +46,7 @@ pub enum InstantiationMode {
     LocalCopy,
 }
 
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable, TyEncodable, TyDecodable)]
 pub enum MonoItem<'tcx> {
     Fn(Instance<'tcx>),
     Static(DefId),
@@ -66,20 +66,7 @@ impl<'tcx> MonoItem<'tcx> {
     // change NON_INCR_MIN_CGU_SIZE as well.
     pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
         match *self {
-            MonoItem::Fn(instance) => {
-                match instance.def {
-                    // "Normal" functions size estimate: the number of
-                    // statements, plus one for the terminator.
-                    InstanceKind::Item(..)
-                    | InstanceKind::DropGlue(..)
-                    | InstanceKind::AsyncDropGlueCtorShim(..) => {
-                        let mir = tcx.instance_mir(instance.def);
-                        mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
-                    }
-                    // Other compiler-generated shims size estimate: 1
-                    _ => 1,
-                }
-            }
+            MonoItem::Fn(instance) => tcx.size_estimate(instance),
             // Conservatively estimate the size of a static declaration or
             // assembly item to be 1.
             MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
@@ -556,3 +543,21 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> {
         Symbol::intern(&cgu_name)
     }
 }
+
+/// See module-level docs of `rustc_monomorphize::collector` on some context for "mentioned" items.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum CollectionMode {
+    /// Collect items that are used, i.e., actually needed for codegen.
+    ///
+    /// Which items are used can depend on optimization levels, as MIR optimizations can remove
+    /// uses.
+    UsedItems,
+    /// Collect items that are mentioned. The goal of this mode is that it is independent of
+    /// optimizations: the set of "mentioned" items is computed before optimizations are run.
+    ///
+    /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
+    /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
+    /// might decide to run them before computing mentioned items.) The key property of this set is
+    /// that it is optimization-independent.
+    MentionedItems,
+}
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index f0e2b7a376c..2bfcd0a6227 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -834,6 +834,11 @@ impl Debug for Statement<'_> {
             Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
             ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
             Nop => write!(fmt, "nop"),
+            BackwardIncompatibleDropHint { ref place, reason: _ } => {
+                // For now, we don't record the reason because there is only one use case,
+                // which is to report breaking change in drop order by Edition 2024
+                write!(fmt, "backward incompatible drop({place:?})")
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 88ed90c3114..1ce735cec63 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -332,9 +332,9 @@ impl<'tcx> Operand<'tcx> {
         span: Span,
     ) -> Operand<'tcx> {
         debug_assert!({
-            let param_env_and_ty = ty::ParamEnv::empty().and(ty);
+            let typing_env = ty::TypingEnv::fully_monomorphized();
             let type_size = tcx
-                .layout_of(param_env_and_ty)
+                .layout_of(typing_env.as_query_input(ty))
                 .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
                 .size;
             let scalar_size = match val {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index f01ac305d3f..fea940ea47c 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -20,7 +20,7 @@ use smallvec::SmallVec;
 use super::{BasicBlock, Const, Local, UserTypeProjection};
 use crate::mir::coverage::CoverageKind;
 use crate::ty::adjustment::PointerCoercion;
-use crate::ty::{self, GenericArgsRef, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex};
+use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex};
 
 /// Represents the "flavors" of MIR.
 ///
@@ -100,13 +100,6 @@ impl MirPhase {
             MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized",
         }
     }
-
-    pub fn param_env<'tcx>(&self, tcx: TyCtxt<'tcx>, body_def_id: DefId) -> ty::ParamEnv<'tcx> {
-        match self {
-            MirPhase::Built | MirPhase::Analysis(_) => tcx.param_env(body_def_id),
-            MirPhase::Runtime(_) => tcx.param_env_reveal_all_normalized(body_def_id),
-        }
-    }
 }
 
 /// See [`MirPhase::Analysis`].
@@ -439,6 +432,18 @@ pub enum StatementKind<'tcx> {
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
+
+    /// Marker statement indicating where `place` would be dropped.
+    /// This is semantically equivalent to `Nop`, so codegen and MIRI should interpret this
+    /// statement as such.
+    /// The only use case of this statement is for linting in MIR to detect temporary lifetime
+    /// changes.
+    BackwardIncompatibleDropHint {
+        /// Place to drop
+        place: Box<Place<'tcx>>,
+        /// Reason for backward incompatibility
+        reason: BackwardIncompatibleDropReason,
+    },
 }
 
 impl StatementKind<'_> {
@@ -459,6 +464,7 @@ impl StatementKind<'_> {
             StatementKind::Intrinsic(..) => "Intrinsic",
             StatementKind::ConstEvalCounter => "ConstEvalCounter",
             StatementKind::Nop => "Nop",
+            StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
         }
     }
 }
@@ -904,6 +910,21 @@ pub enum TerminatorKind<'tcx> {
     },
 }
 
+#[derive(
+    Clone,
+    Debug,
+    TyEncodable,
+    TyDecodable,
+    Hash,
+    HashStable,
+    PartialEq,
+    TypeFoldable,
+    TypeVisitable
+)]
+pub enum BackwardIncompatibleDropReason {
+    Edition2024,
+}
+
 impl TerminatorKind<'_> {
     /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
     /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 9f9ee8497b6..62c340d99e3 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -452,6 +452,7 @@ macro_rules! make_mir_visitor {
                     }
                     StatementKind::ConstEvalCounter => {}
                     StatementKind::Nop => {}
+                    StatementKind::BackwardIncompatibleDropHint { .. } => {}
                 }
             }
 
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 1d4c36e28bd..013847f0b2d 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -216,6 +216,10 @@ impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) {
     type Result = [u8; size_of::<(&'static (), &'static [()])>()];
 }
 
+impl<T0, T1> EraseType for (&'_ [T0], &'_ [T1]) {
+    type Result = [u8; size_of::<(&'static [()], &'static [()])>()];
+}
+
 impl<T0> EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) {
     type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
 }
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index fe28ef0f70c..970dc72e1ff 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -2,11 +2,13 @@
 
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
 use rustc_hir::hir_id::{HirId, OwnerId};
+use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{DUMMY_SP, Span};
 
 use crate::infer::canonical::CanonicalQueryInput;
+use crate::mir::mono::CollectionMode;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::layout::{TyAndLayout, ValidityRequirement};
 use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
@@ -110,7 +112,7 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
 }
 
 impl Key for CrateNum {
-    type Cache<V> = VecCache<Self, V>;
+    type Cache<V> = VecCache<Self, V, DepNodeIndex>;
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -127,7 +129,7 @@ impl AsLocalKey for CrateNum {
 }
 
 impl Key for OwnerId {
-    type Cache<V> = VecCache<Self, V>;
+    type Cache<V> = VecCache<Self, V, DepNodeIndex>;
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.to_def_id().default_span(tcx)
@@ -139,7 +141,7 @@ impl Key for OwnerId {
 }
 
 impl Key for LocalDefId {
-    type Cache<V> = VecCache<Self, V>;
+    type Cache<V> = VecCache<Self, V, DepNodeIndex>;
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.to_def_id().default_span(tcx)
@@ -358,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) {
     }
 }
 
+impl<'tcx> Key for ty::ParamEnvAnd<'tcx, Ty<'tcx>> {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for ty::TraitRef<'tcx> {
     type Cache<V> = DefaultCache<Self, V>;
 
@@ -454,7 +464,7 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> {
     }
 }
 
-impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
+impl<'tcx, T: Key> Key for ty::PseudoCanonicalInput<'tcx, T> {
     type Cache<V> = DefaultCache<Self, V>;
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -574,7 +584,7 @@ impl Key for (LocalDefId, HirId) {
     }
 }
 
-impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
+impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) {
     type Cache<V> = DefaultCache<Self, V>;
 
     // Just forward to `Ty<'tcx>`
@@ -590,3 +600,11 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
         }
     }
 }
+
+impl<'tcx> Key for (ty::Instance<'tcx>, CollectionMode) {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4e3668822ec..76338be33aa 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -40,6 +40,7 @@ use rustc_session::cstore::{
 };
 use rustc_session::lint::LintExpectationId;
 use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::spec::PanicStrategy;
@@ -59,7 +60,7 @@ use crate::mir::interpret::{
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
     EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
 };
-use crate::mir::mono::CodegenUnit;
+use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem};
 use crate::query::erase::{Erase, erase, restore};
 use crate::query::plumbing::{
     CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at,
@@ -80,8 +81,8 @@ use crate::ty::layout::ValidityRequirement;
 use crate::ty::print::{PrintTraitRefExt, describe_as_module};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{
-    self, CrateInherentImpls, GenericArg, GenericArgsRef, ParamEnvAnd, Ty, TyCtxt, TyCtxtFeed,
-    UnusedGenericParams,
+    self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
+    TyCtxtFeed, UnusedGenericParams,
 };
 use crate::{dep_graph, mir, thir};
 
@@ -696,7 +697,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query implied_const_bounds(
+    query explicit_implied_const_bounds(
         key: DefId
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
         desc { |tcx| "computing the implied `~const` bounds for `{}`",
@@ -1094,7 +1095,7 @@ rustc_queries! {
     /// Evaluates a constant and returns the computed allocation.
     ///
     /// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead.
-    query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+    query eval_to_allocation_raw(key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>)
         -> EvalToAllocationRawResult<'tcx> {
         desc { |tcx|
             "const-evaluating + checking `{}`",
@@ -1120,7 +1121,7 @@ rustc_queries! {
     ///
     /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
     /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
-    query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+    query eval_to_const_value_raw(key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>)
         -> EvalToConstValueResult<'tcx> {
         desc { |tcx|
             "simplifying constant for the type system `{}`",
@@ -1132,7 +1133,7 @@ rustc_queries! {
     /// Evaluate a constant and convert it to a type level constant or
     /// return `None` if that is not possible.
     query eval_to_valtree(
-        key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>
+        key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>
     ) -> EvalToValTreeResult<'tcx> {
         desc { "evaluating type-level constant" }
     }
@@ -1340,10 +1341,10 @@ rustc_queries! {
     }
 
     query codegen_select_candidate(
-        key: (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>)
+        key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>
     ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
         cache_on_disk_if { true }
-        desc { |tcx| "computing candidate for `{}`", key.1 }
+        desc { |tcx| "computing candidate for `{}`", key.value }
     }
 
     /// Return all `impl` blocks in the current crate.
@@ -1389,31 +1390,31 @@ rustc_queries! {
 
     /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
     /// `ty.is_copy()`, etc, since that will prune the environment where possible.
-    query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Copy`", env.value }
     }
     /// Query backing `Ty::is_sized`.
-    query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Sized`", env.value }
     }
     /// Query backing `Ty::is_freeze`.
-    query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query is_freeze_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is freeze", env.value }
     }
     /// Query backing `Ty::is_unpin`.
-    query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query is_unpin_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Unpin`", env.value }
     }
     /// Query backing `Ty::needs_drop`.
-    query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query needs_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` needs drop", env.value }
     }
     /// Query backing `Ty::needs_async_drop`.
-    query needs_async_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query needs_async_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` needs async drop", env.value }
     }
     /// Query backing `Ty::has_significant_drop_raw`.
-    query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    query has_significant_drop_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` has a significant drop", env.value }
     }
 
@@ -1447,10 +1448,32 @@ rustc_queries! {
         cache_on_disk_if { false }
     }
 
+    /// Returns a list of types which (a) have a potentially significant destructor
+    /// and (b) may be dropped as a result of dropping a value of some type `ty`
+    /// (in the given environment).
+    ///
+    /// The idea of "significant" drop is somewhat informal and is used only for
+    /// diagnostics and edition migrations. The idea is that a significant drop may have
+    /// some visible side-effect on execution; freeing memory is NOT considered a side-effect.
+    /// The rules are as follows:
+    /// * Type with no explicit drop impl do not have significant drop.
+    /// * Types with a drop impl are assumed to have significant drop unless they have a `#[rustc_insignificant_dtor]` annotation.
+    ///
+    /// Note that insignificant drop is a "shallow" property. A type like `Vec<LockGuard>` does not
+    /// have significant drop but the type `LockGuard` does, and so if `ty  = Vec<LockGuard>`
+    /// then the return value would be `&[LockGuard]`.
+    /// *IMPORTANT*: *DO NOT* run this query before promoted MIR body is constructed,
+    /// because this query partially depends on that query.
+    /// Otherwise, there is a risk of query cycles.
+    query list_significant_drop_tys(ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx ty::List<Ty<'tcx>> {
+        desc { |tcx| "computing when `{}` has a significant destructor", ty.value }
+        cache_on_disk_if { false }
+    }
+
     /// Computes the layout of a type. Note that this implicitly
     /// executes in "reveal all" mode, and will normalize the input type.
     query layout_of(
-        key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+        key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>
     ) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
         depth_limit
         desc { "computing layout of `{}`", key.value }
@@ -1463,7 +1486,7 @@ rustc_queries! {
     /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
     /// instead, where the instance is an `InstanceKind::Virtual`.
     query fn_abi_of_fn_ptr(
-        key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+        key: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
     ) -> Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
         desc { "computing call ABI of `{}` function pointers", key.value.0 }
     }
@@ -1474,7 +1497,7 @@ rustc_queries! {
     /// NB: that includes virtual calls, which are represented by "direct calls"
     /// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
     query fn_abi_of_instance(
-        key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+        key: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
     ) -> Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
         desc { "computing call ABI of `{}`", key.value.0 }
     }
@@ -2087,7 +2110,7 @@ rustc_queries! {
 
     /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
     query try_normalize_generic_arg_after_erasing_regions(
-        goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+        goal: PseudoCanonicalInput<'tcx, GenericArg<'tcx>>
     ) -> Result<GenericArg<'tcx>, NoSolution> {
         desc { "normalizing `{}`", goal.value }
     }
@@ -2244,7 +2267,7 @@ rustc_queries! {
     ///    from `Ok(None)` to avoid misleading diagnostics when an error
     ///    has already been/will be emitted, for the original cause.
     query resolve_instance_raw(
-        key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>
+        key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)>
     ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
         desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
     }
@@ -2282,7 +2305,7 @@ rustc_queries! {
         desc { "computing the backend features for CLI flags" }
     }
 
-    query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> {
+    query check_validity_requirement(key: (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> {
         desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
     }
 
@@ -2339,6 +2362,16 @@ rustc_queries! {
         arena_cache
         desc { "functions to skip for move-size check" }
     }
+
+    query items_of_instance(key: (ty::Instance<'tcx>, CollectionMode)) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) {
+        desc { "collecting items used by `{}`", key.0 }
+        cache_on_disk_if { true }
+    }
+
+    query size_estimate(key: ty::Instance<'tcx>) -> usize {
+        desc { "estimating codegen size of `{}`", key }
+        cache_on_disk_if { true }
+    }
 }
 
 rustc_query_append! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 8b77a4a81ca..3849cb72668 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -12,6 +12,7 @@ use rustc_index::{Idx, IndexVec};
 use rustc_macros::{Decodable, Encodable};
 use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
+use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::{self, interpret};
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -22,7 +23,7 @@ use rustc_session::Session;
 use rustc_span::hygiene::{
     ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
 };
-use rustc_span::source_map::SourceMap;
+use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::{
     BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span,
     SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
@@ -773,6 +774,13 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsm
     }
 }
 
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Spanned<MonoItem<'tcx>>] {
+    #[inline]
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+        RefDecodable::decode(d)
+    }
+}
+
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     for &'tcx crate::traits::specialization_graph::Graph
 {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 45ceb0a555d..9cf6bc1b777 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -247,13 +247,24 @@ pub struct Expr<'tcx> {
     pub ty: Ty<'tcx>,
 
     /// The lifetime of this expression if it should be spilled into a
-    /// temporary; should be `None` only if in a constant context
-    pub temp_lifetime: Option<region::Scope>,
+    /// temporary
+    pub temp_lifetime: TempLifetime,
 
     /// span of the expression in the source
     pub span: Span,
 }
 
+/// Temporary lifetime information for THIR expressions
+#[derive(Clone, Copy, Debug, HashStable)]
+pub struct TempLifetime {
+    /// Lifetime for temporaries as expected.
+    /// This should be `None` in a constant context.
+    pub temp_lifetime: Option<region::Scope>,
+    /// If `Some(lt)`, indicates that the lifetime of this temporary will change to `lt` in a future edition.
+    /// If `None`, then no changes are expected, or lints are disabled.
+    pub backwards_incompatible: Option<region::Scope>,
+}
+
 #[derive(Clone, Debug, HashStable)]
 pub enum ExprKind<'tcx> {
     /// `Scope`s are used to explicitly mark destruction scopes,
@@ -645,7 +656,7 @@ impl<'tcx> Pat<'tcx> {
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern }
             | DerefPattern { subpattern, .. }
-            | InlineConstant { subpattern, .. } => subpattern.walk_(it),
+            | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
             }
@@ -788,12 +799,17 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
-    /// Inline constant found while lowering a pattern.
-    InlineConstant {
-        /// [LocalDefId] of the constant, we need this so that we have a
+    /// Pattern obtained by converting a constant (inline or named) to its pattern
+    /// representation using `const_to_pat`.
+    ExpandedConstant {
+        /// [DefId] of the constant, we need this so that we have a
         /// reference that can be used by unsafety checking to visit nested
-        /// unevaluated constants.
-        def: LocalDefId,
+        /// unevaluated constants and for diagnostics. If the `DefId` doesn't
+        /// correspond to a local crate, it points at the `const` item.
+        def_id: DefId,
+        /// If `false`, then `def_id` points at a `const` item, otherwise it
+        /// corresponds to a local inline const.
+        is_inline: bool,
         /// If the inline constant is used in a range pattern, this subpattern
         /// represents the range (if both ends are inline constants, there will
         /// be multiple InlineConstant wrappers).
@@ -905,7 +921,7 @@ impl<'tcx> PatRange<'tcx> {
         &self,
         value: mir::Const<'tcx>,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<bool> {
         use Ordering::*;
         debug_assert_eq!(self.ty, value.ty());
@@ -913,10 +929,10 @@ impl<'tcx> PatRange<'tcx> {
         let value = PatRangeBoundary::Finite(value);
         // For performance, it's important to only do the second comparison if necessary.
         Some(
-            match self.lo.compare_with(value, ty, tcx, param_env)? {
+            match self.lo.compare_with(value, ty, tcx, typing_env)? {
                 Less | Equal => true,
                 Greater => false,
-            } && match value.compare_with(self.hi, ty, tcx, param_env)? {
+            } && match value.compare_with(self.hi, ty, tcx, typing_env)? {
                 Less => true,
                 Equal => self.end == RangeEnd::Included,
                 Greater => false,
@@ -929,17 +945,17 @@ impl<'tcx> PatRange<'tcx> {
         &self,
         other: &Self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<bool> {
         use Ordering::*;
         debug_assert_eq!(self.ty, other.ty);
         // For performance, it's important to only do the second comparison if necessary.
         Some(
-            match other.lo.compare_with(self.hi, self.ty, tcx, param_env)? {
+            match other.lo.compare_with(self.hi, self.ty, tcx, typing_env)? {
                 Less => true,
                 Equal => self.end == RangeEnd::Included,
                 Greater => false,
-            } && match self.lo.compare_with(other.hi, self.ty, tcx, param_env)? {
+            } && match self.lo.compare_with(other.hi, self.ty, tcx, typing_env)? {
                 Less => true,
                 Equal => other.end == RangeEnd::Included,
                 Greater => false,
@@ -985,9 +1001,14 @@ impl<'tcx> PatRangeBoundary<'tcx> {
             Self::NegInfinity | Self::PosInfinity => None,
         }
     }
-    pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
+    pub fn eval_bits(
+        self,
+        ty: Ty<'tcx>,
+        tcx: TyCtxt<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+    ) -> u128 {
         match self {
-            Self::Finite(value) => value.eval_bits(tcx, param_env),
+            Self::Finite(value) => value.eval_bits(tcx, typing_env),
             Self::NegInfinity => {
                 // Unwrap is ok because the type is known to be numeric.
                 ty.numeric_min_and_max_as_bits(tcx).unwrap().0
@@ -999,13 +1020,13 @@ impl<'tcx> PatRangeBoundary<'tcx> {
         }
     }
 
-    #[instrument(skip(tcx, param_env), level = "debug", ret)]
+    #[instrument(skip(tcx, typing_env), level = "debug", ret)]
     pub fn compare_with(
         self,
         other: Self,
         ty: Ty<'tcx>,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<Ordering> {
         use PatRangeBoundary::*;
         match (self, other) {
@@ -1034,8 +1055,8 @@ impl<'tcx> PatRangeBoundary<'tcx> {
             _ => {}
         }
 
-        let a = self.eval_bits(ty, tcx, param_env);
-        let b = other.eval_bits(ty, tcx, param_env);
+        let a = self.eval_bits(ty, tcx, typing_env);
+        let b = other.eval_bits(ty, tcx, typing_env);
 
         match ty.kind() {
             ty::Float(ty::FloatTy::F16) => {
@@ -1082,7 +1103,7 @@ mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Block, 48);
-    static_assert_size!(Expr<'_>, 64);
+    static_assert_size!(Expr<'_>, 72);
     static_assert_size!(ExprKind<'_>, 40);
     static_assert_size!(Pat<'_>, 64);
     static_assert_size!(PatKind<'_>, 48);
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 36f0e3d890c..81202a6eaad 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -247,7 +247,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
             }
         }
         Constant { value: _ } => {}
-        InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
+        ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix.iter() {
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 0773eb7a3be..79d56702be2 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -498,12 +498,13 @@ impl<'tcx> AdtDef<'tcx> {
         expr_did: DefId,
     ) -> Result<Discr<'tcx>, ErrorGuaranteed> {
         assert!(self.is_enum());
-        let param_env = tcx.param_env(expr_did);
+
         let repr_type = self.repr().discr_type();
         match tcx.const_eval_poly(expr_did) {
             Ok(val) => {
+                let typing_env = ty::TypingEnv::post_analysis(tcx, expr_did);
                 let ty = repr_type.to_ty(tcx);
-                if let Some(b) = val.try_to_bits_for_ty(tcx, param_env, ty) {
+                if let Some(b) = val.try_to_bits_for_ty(tcx, typing_env, ty) {
                     trace!("discriminants: {} ({:?})", b, repr_type);
                     Ok(Discr { val: b, ty })
                 } else {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index b5358f0ca35..47a84d4b258 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -13,9 +13,11 @@ use std::marker::DiscriminantKind;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::TyCtxt;
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::Span;
+use rustc_span::source_map::Spanned;
 pub use rustc_type_ir::{TyDecoder, TyEncoder};
 
 use crate::arena::ArenaAllocatable;
@@ -397,6 +399,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [Spanned<MonoItem<'tcx>>] {
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder
+            .interner()
+            .arena
+            .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder)))
+    }
+}
+
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     for ty::List<ty::BoundVariableKind>
 {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 5689f3d4265..d853edb34c9 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,15 +1,16 @@
+use std::borrow::Cow;
+
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{self as hir, HirId};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::{self as hir};
 use rustc_macros::HashStable;
 use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
-use crate::middle::resolve_bound_vars as rbv;
 use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+use crate::ty::{self, GenericArgs, Ty, TyCtxt, TypeVisitableExt};
 
 mod int;
 mod kind;
@@ -142,7 +143,7 @@ impl<'tcx> Const<'tcx> {
     pub fn new_error_with_message<S: Into<MultiSpan>>(
         tcx: TyCtxt<'tcx>,
         span: S,
-        msg: &'static str,
+        msg: impl Into<Cow<'static, str>>,
     ) -> Const<'tcx> {
         let reported = tcx.dcx().span_delayed_bug(span, msg);
         Const::new_error(tcx, reported)
@@ -183,46 +184,8 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
     }
 }
 
-/// In some cases, [`hir::ConstArg`]s that are being used in the type system
-/// through const generics need to have their type "fed" to them
-/// using the query system.
-///
-/// Use this enum with [`Const::from_const_arg`] to instruct it with the
-/// desired behavior.
-#[derive(Debug, Clone, Copy)]
-pub enum FeedConstTy {
-    /// Feed the type.
-    ///
-    /// The `DefId` belongs to the const param that we are supplying
-    /// this (anon) const arg to.
-    Param(DefId),
-    /// Don't feed the type.
-    No,
-}
-
 impl<'tcx> Const<'tcx> {
-    /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self).
-    #[instrument(skip(tcx), level = "debug")]
-    pub fn from_const_arg(
-        tcx: TyCtxt<'tcx>,
-        const_arg: &'tcx hir::ConstArg<'tcx>,
-        feed: FeedConstTy,
-    ) -> Self {
-        if let FeedConstTy::Param(param_def_id) = feed
-            && let hir::ConstArgKind::Anon(anon) = &const_arg.kind
-        {
-            tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
-        }
-
-        match const_arg.kind {
-            hir::ConstArgKind::Path(qpath) => {
-                // FIXME(min_generic_const_args): for now only params are lowered to ConstArgKind::Path
-                Self::from_param(tcx, qpath, const_arg.hir_id)
-            }
-            hir::ConstArgKind::Anon(anon) => Self::from_anon_const(tcx, anon.def_id),
-        }
-    }
-
+    // FIXME: move this and try_from_lit to hir_ty_lowering like lower_const_arg/from_const_arg
     /// Literals and const generic parameters are eagerly converted to a constant, everything else
     /// becomes `Unevaluated`.
     #[instrument(skip(tcx), level = "debug")]
@@ -240,7 +203,7 @@ impl<'tcx> Const<'tcx> {
 
         let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
 
-        match Self::try_from_lit_or_param(tcx, ty, expr) {
+        match Self::try_from_lit(tcx, ty, expr) {
             Some(v) => v,
             None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst {
                 def: def.to_def_id(),
@@ -249,40 +212,8 @@ impl<'tcx> Const<'tcx> {
         }
     }
 
-    /// Lower a const param to a [`Const`].
-    ///
-    /// IMPORTANT: `qpath` must be a const param, otherwise this will panic
-    fn from_param(tcx: TyCtxt<'tcx>, qpath: hir::QPath<'tcx>, hir_id: HirId) -> Self {
-        let hir::QPath::Resolved(_, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }) =
-            qpath
-        else {
-            span_bug!(qpath.span(), "non-param {qpath:?} passed to Const::from_param")
-        };
-
-        match tcx.named_bound_var(hir_id) {
-            Some(rbv::ResolvedArg::EarlyBound(_)) => {
-                // Find the name and index of the const parameter by indexing the generics of
-                // the parent item and construct a `ParamConst`.
-                let item_def_id = tcx.parent(def_id);
-                let generics = tcx.generics_of(item_def_id);
-                let index = generics.param_def_id_to_index[&def_id];
-                let name = tcx.item_name(def_id);
-                ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
-            }
-            Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
-                ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
-            }
-            Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
-            arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
-        }
-    }
-
     #[instrument(skip(tcx), level = "debug")]
-    fn try_from_lit_or_param(
-        tcx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-        expr: &'tcx hir::Expr<'tcx>,
-    ) -> Option<Self> {
+    fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option<Self> {
         // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
         // currently have to be wrapped in curly brackets, so it's necessary to special-case.
         let expr = match &expr.kind {
@@ -321,7 +252,7 @@ impl<'tcx> Const<'tcx> {
                 Err(e) => {
                     tcx.dcx().span_delayed_bug(
                         expr.span,
-                        format!("Const::from_anon_const: couldn't lit_to_const {e:?}"),
+                        format!("Const::try_from_lit: couldn't lit_to_const {e:?}"),
                     );
                 }
             }
@@ -330,17 +261,22 @@ impl<'tcx> Const<'tcx> {
         None
     }
 
-    #[inline]
     /// Creates a constant with the given integer value and interns it.
-    pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
+    #[inline]
+    pub fn from_bits(
+        tcx: TyCtxt<'tcx>,
+        bits: u128,
+        typing_env: ty::TypingEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Self {
         let size = tcx
-            .layout_of(ty)
+            .layout_of(typing_env.as_query_input(ty))
             .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
             .size;
         ty::Const::new_value(
             tcx,
             ty::ValTree::from_scalar_int(ScalarInt::try_from_uint(bits, size).unwrap()),
-            ty.value,
+            ty,
         )
     }
 
@@ -353,13 +289,13 @@ impl<'tcx> Const<'tcx> {
     #[inline]
     /// Creates an interned bool constant.
     pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
-        Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
+        Self::from_bits(tcx, v as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.bool)
     }
 
     #[inline]
     /// Creates an interned usize constant.
     pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
-        Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
+        Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
     }
 
     /// Panics if self.kind != ty::ConstKind::Value
@@ -393,15 +329,15 @@ impl<'tcx> Const<'tcx> {
         self.try_to_valtree()?.0.try_to_target_usize(tcx)
     }
 
-    #[inline]
     /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
     /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
     /// contains const generic parameters or pointers).
-    pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
+    #[inline]
+    pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
         let (scalar, ty) = self.try_to_scalar()?;
         let scalar = scalar.try_to_scalar_int().ok()?;
-        let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
-        // if `ty` does not depend on generic parameters, use an empty param_env
+        let input = typing_env.with_reveal_all_normalized(tcx).as_query_input(ty);
+        let size = tcx.layout_of(input).ok()?.size;
         Some(scalar.to_bits(size))
     }
 
@@ -409,20 +345,3 @@ impl<'tcx> Const<'tcx> {
         matches!(self.kind(), ty::ConstKind::Infer(_))
     }
 }
-
-pub fn const_param_default<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
-    let default_ct = match tcx.hir_node_by_def_id(def_id) {
-        hir::Node::GenericParam(hir::GenericParam {
-            kind: hir::GenericParamKind::Const { default: Some(ct), .. },
-            ..
-        }) => ct,
-        _ => span_bug!(
-            tcx.def_span(def_id),
-            "`const_param_default` expected a generic parameter with a constant"
-        ),
-    };
-    ty::EarlyBinder::bind(Const::from_const_arg(tcx, default_ct, FeedConstTy::No))
-}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 84ac281c258..55c29825fbc 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -30,7 +30,7 @@ use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan,
 };
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::definitions::Definitions;
 use rustc_hir::intravisit::Visitor;
@@ -230,7 +230,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
             DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
             DefKind::TyAlias => ty::AliasTermKind::WeakTy,
             DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
-            DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
+            DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => {
+                ty::AliasTermKind::UnevaluatedConst
+            }
             kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
         }
     }
@@ -374,7 +376,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
     }
 
-    fn is_const_impl(self, def_id: DefId) -> bool {
+    fn impl_is_const(self, def_id: DefId) -> bool {
+        self.is_conditionally_const(def_id)
+    }
+
+    fn fn_is_const(self, def_id: DefId) -> bool {
         self.is_conditionally_const(def_id)
     }
 
@@ -387,12 +393,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         )
     }
 
-    fn implied_const_bounds(
+    fn explicit_implied_const_bounds(
         self,
         def_id: DefId,
     ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
         ty::EarlyBinder::bind(
-            self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
+            self.explicit_implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
         )
     }
 
@@ -596,11 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.coroutine_is_async_gen(coroutine_def_id)
     }
 
-    fn layout_is_pointer_like(self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
-        self.layout_of(self.erase_regions(param_env.and(ty)))
-            .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout))
-    }
-
     type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
     fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
         self.unsizing_params_for_adt(adt_def_id)
@@ -674,7 +675,6 @@ bidirectional_lang_item_map! {
     Metadata,
     Option,
     PointeeTrait,
-    PointerLike,
     Poll,
     Sized,
     TransmuteTrait,
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
index bf741f63a3d..505c7278176 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -3,7 +3,7 @@ use smallvec::SmallVec;
 use tracing::instrument;
 
 use crate::ty::context::TyCtxt;
-use crate::ty::{self, DefId, OpaqueTypeKey, ParamEnv, Ty};
+use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TypingEnv};
 
 /// Represents whether some type is inhabited in a given context.
 /// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
@@ -35,8 +35,13 @@ pub enum InhabitedPredicate<'tcx> {
 
 impl<'tcx> InhabitedPredicate<'tcx> {
     /// Returns true if the corresponding type is inhabited in the given `ParamEnv` and module.
-    pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool {
-        self.apply_revealing_opaque(tcx, param_env, module_def_id, &|_| None)
+    pub fn apply(
+        self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        module_def_id: DefId,
+    ) -> bool {
+        self.apply_revealing_opaque(tcx, typing_env, module_def_id, &|_| None)
     }
 
     /// Returns true if the corresponding type is inhabited in the given `ParamEnv` and module,
@@ -44,13 +49,13 @@ impl<'tcx> InhabitedPredicate<'tcx> {
     pub fn apply_revealing_opaque(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
+        typing_env: TypingEnv<'tcx>,
         module_def_id: DefId,
         reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>>,
     ) -> bool {
         let Ok(result) = self.apply_inner::<!>(
             tcx,
-            param_env,
+            typing_env,
             &mut Default::default(),
             &|id| Ok(tcx.is_descendant_of(module_def_id, id)),
             reveal_opaque,
@@ -59,25 +64,25 @@ impl<'tcx> InhabitedPredicate<'tcx> {
     }
 
     /// Same as `apply`, but returns `None` if self contains a module predicate
-    pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.apply_inner(tcx, param_env, &mut Default::default(), &|_| Err(()), &|_| None).ok()
+    pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> Option<bool> {
+        self.apply_inner(tcx, typing_env, &mut Default::default(), &|_| Err(()), &|_| None).ok()
     }
 
     /// Same as `apply`, but `NotInModule(_)` predicates yield `false`. That is,
     /// privately uninhabited types are considered always uninhabited.
-    pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> bool {
+    pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool {
         let Ok(result) =
-            self.apply_inner::<!>(tcx, param_env, &mut Default::default(), &|_| Ok(true), &|_| {
+            self.apply_inner::<!>(tcx, typing_env, &mut Default::default(), &|_| Ok(true), &|_| {
                 None
             });
         result
     }
 
-    #[instrument(level = "debug", skip(tcx, param_env, in_module, reveal_opaque), ret)]
+    #[instrument(level = "debug", skip(tcx, typing_env, in_module, reveal_opaque), ret)]
     fn apply_inner<E: std::fmt::Debug>(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
+        typing_env: TypingEnv<'tcx>,
         eval_stack: &mut SmallVec<[Ty<'tcx>; 1]>, // for cycle detection
         in_module: &impl Fn(DefId) -> Result<bool, E>,
         reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>>,
@@ -94,7 +99,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
             // we have a param_env available, we can do better.
             Self::GenericType(t) => {
                 let normalized_pred = tcx
-                    .try_normalize_erasing_regions(param_env, t)
+                    .try_normalize_erasing_regions(typing_env, t)
                     .map_or(self, |t| t.inhabited_predicate(tcx));
                 match normalized_pred {
                     // We don't have more information than we started with, so consider inhabited.
@@ -107,7 +112,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
                         }
                         eval_stack.push(t);
                         let ret =
-                            pred.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque);
+                            pred.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque);
                         eval_stack.pop();
                         ret
                     }
@@ -126,7 +131,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
                     eval_stack.push(t);
                     let ret = t.inhabited_predicate(tcx).apply_inner(
                         tcx,
-                        param_env,
+                        typing_env,
                         eval_stack,
                         in_module,
                         reveal_opaque,
@@ -136,10 +141,10 @@ impl<'tcx> InhabitedPredicate<'tcx> {
                 }
             },
             Self::And([a, b]) => try_and(a, b, |x| {
-                x.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque)
+                x.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque)
             }),
             Self::Or([a, b]) => try_or(a, b, |x| {
-                x.apply_inner(tcx, param_env, eval_stack, in_module, reveal_opaque)
+                x.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque)
             }),
         }
     }
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index dd00db8635f..4a5f6d80f24 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -181,18 +181,18 @@ impl<'tcx> Ty<'tcx> {
         self,
         tcx: TyCtxt<'tcx>,
         module: DefId,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> bool {
-        self.inhabited_predicate(tcx).apply(tcx, param_env, module)
+        self.inhabited_predicate(tcx).apply(tcx, typing_env, module)
     }
 
     /// Returns true if the type is uninhabited without regard to visibility
     pub fn is_privately_uninhabited(
         self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> bool {
-        !self.inhabited_predicate(tcx).apply_ignore_module(tcx, param_env)
+        !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 0d1c56f0d38..dab3e18de33 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -178,9 +178,9 @@ pub enum InstanceKind<'tcx> {
 impl<'tcx> Instance<'tcx> {
     /// Returns the `Ty` corresponding to this `Instance`, with generic instantiations applied and
     /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
-    pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
+    pub fn ty(&self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Ty<'tcx> {
         let ty = tcx.type_of(self.def.def_id());
-        tcx.instantiate_and_normalize_erasing_regions(self.args, param_env, ty)
+        tcx.instantiate_and_normalize_erasing_regions(self.args, typing_env, ty)
     }
 
     /// Finds a crate that contains a monomorphization of this instance that
@@ -519,7 +519,7 @@ impl<'tcx> Instance<'tcx> {
     #[instrument(level = "debug", skip(tcx), ret)]
     pub fn try_resolve(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
     ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
@@ -537,17 +537,12 @@ impl<'tcx> Instance<'tcx> {
 
         // All regions in the result of this query are erased, so it's
         // fine to erase all of the input regions.
-
-        // HACK(eddyb) erase regions in `args` first, so that `param_env.and(...)`
-        // below is more likely to ignore the bounds in scope (e.g. if the only
-        // generic parameters mentioned by `args` were lifetime ones).
-        let args = tcx.erase_regions(args);
-        tcx.resolve_instance_raw(tcx.erase_regions(param_env.and((def_id, args))))
+        tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args))))
     }
 
     pub fn expect_resolve(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
         span: Span,
@@ -558,7 +553,7 @@ impl<'tcx> Instance<'tcx> {
         let span_or_local_def_span =
             || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span };
 
-        match ty::Instance::try_resolve(tcx, param_env, def_id, args) {
+        match ty::Instance::try_resolve(tcx, typing_env, def_id, args) {
             Ok(Some(instance)) => instance,
             Ok(None) => {
                 let type_length = type_length(args);
@@ -600,7 +595,7 @@ impl<'tcx> Instance<'tcx> {
 
     pub fn resolve_for_fn_ptr(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
     ) -> Option<Instance<'tcx>> {
@@ -608,7 +603,7 @@ impl<'tcx> Instance<'tcx> {
         // Use either `resolve_closure` or `resolve_for_vtable`
         assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
         let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
-        Instance::try_resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
+        Instance::try_resolve(tcx, typing_env, def_id, args).ok().flatten().map(|mut resolved| {
             match resolved.def {
                 InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => {
                     debug!(" => fn pointer created for function with #[track_caller]");
@@ -648,7 +643,7 @@ impl<'tcx> Instance<'tcx> {
 
     pub fn expect_resolve_for_vtable(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
         span: Span,
@@ -664,7 +659,7 @@ impl<'tcx> Instance<'tcx> {
             return Instance { def: InstanceKind::VTableShim(def_id), args };
         }
 
-        let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, span);
+        let mut resolved = Instance::expect_resolve(tcx, typing_env, def_id, args, span);
 
         let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
         match resolved.def {
@@ -743,7 +738,7 @@ impl<'tcx> Instance<'tcx> {
         let args = tcx.mk_args(&[ty.into()]);
         Instance::expect_resolve(
             tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             def_id,
             args,
             ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP),
@@ -755,7 +750,7 @@ impl<'tcx> Instance<'tcx> {
         let args = tcx.mk_args(&[ty.into()]);
         Instance::expect_resolve(
             tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             def_id,
             args,
             ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP),
@@ -883,16 +878,16 @@ impl<'tcx> Instance<'tcx> {
     pub fn instantiate_mir_and_normalize_erasing_regions<T>(
         &self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         v: EarlyBinder<'tcx, T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         if let Some(args) = self.args_for_mir_body() {
-            tcx.instantiate_and_normalize_erasing_regions(args, param_env, v)
+            tcx.instantiate_and_normalize_erasing_regions(args, typing_env, v)
         } else {
-            tcx.normalize_erasing_regions(param_env, v.instantiate_identity())
+            tcx.normalize_erasing_regions(typing_env, v.instantiate_identity())
         }
     }
 
@@ -901,21 +896,21 @@ impl<'tcx> Instance<'tcx> {
     pub fn try_instantiate_mir_and_normalize_erasing_regions<T>(
         &self,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         v: EarlyBinder<'tcx, T>,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         if let Some(args) = self.args_for_mir_body() {
-            tcx.try_instantiate_and_normalize_erasing_regions(args, param_env, v)
+            tcx.try_instantiate_and_normalize_erasing_regions(args, typing_env, v)
         } else {
             // We're using `instantiate_identity` as e.g.
             // `FnPtrShim` is separately generated for every
             // instantiation of the `FnDef`, so the MIR body
             // is already instantiated. Any generic parameters it
             // contains are generic parameters from the caller.
-            tcx.try_normalize_erasing_regions(param_env, v.instantiate_identity())
+            tcx.try_normalize_erasing_regions(typing_env, v.instantiate_identity())
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index a0eb9029319..fc29b438d3a 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -297,12 +297,12 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
 #[derive(Clone, Copy)]
 pub struct LayoutCx<'tcx> {
     pub calc: abi::LayoutCalculator<TyCtxt<'tcx>>,
-    pub param_env: ty::ParamEnv<'tcx>,
+    pub typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> LayoutCx<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
-        Self { calc: abi::LayoutCalculator::new(tcx), param_env }
+    pub fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self {
+        Self { calc: abi::LayoutCalculator::new(tcx), typing_env }
     }
 }
 
@@ -337,12 +337,12 @@ impl<'tcx> SizeSkeleton<'tcx> {
     pub fn compute(
         ty: Ty<'tcx>,
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
         debug_assert!(!ty.has_non_region_infer());
 
         // First try computing a static layout.
-        let err = match tcx.layout_of(param_env.and(ty)) {
+        let err = match tcx.layout_of(typing_env.as_query_input(ty)) {
             Ok(layout) => {
                 if layout.is_sized() {
                     return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
@@ -367,7 +367,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
 
                 let tail = tcx.struct_tail_raw(
                     pointee,
-                    |ty| match tcx.try_normalize_erasing_regions(param_env, ty) {
+                    |ty| match tcx.try_normalize_erasing_regions(typing_env, ty) {
                         Ok(ty) => ty,
                         Err(e) => Ty::new_error_with_message(
                             tcx,
@@ -402,7 +402,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
                     return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
                 }
 
-                match SizeSkeleton::compute(inner, tcx, param_env)? {
+                match SizeSkeleton::compute(inner, tcx, typing_env)? {
                     // This may succeed because the multiplication of two types may overflow
                     // but a single size of a nested array will not.
                     SizeSkeleton::Known(s, a) => {
@@ -432,7 +432,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
                     let i = VariantIdx::from_usize(i);
                     let fields =
                         def.variant(i).fields.iter().map(|field| {
-                            SizeSkeleton::compute(field.ty(tcx, args), tcx, param_env)
+                            SizeSkeleton::compute(field.ty(tcx, args), tcx, typing_env)
                         });
                     let mut ptr = None;
                     for field in fields {
@@ -491,11 +491,11 @@ impl<'tcx> SizeSkeleton<'tcx> {
             }
 
             ty::Alias(..) => {
-                let normalized = tcx.normalize_erasing_regions(param_env, ty);
+                let normalized = tcx.normalize_erasing_regions(typing_env, ty);
                 if ty == normalized {
                     Err(err)
                 } else {
-                    SizeSkeleton::compute(normalized, tcx, param_env)
+                    SizeSkeleton::compute(normalized, tcx, typing_env)
                 }
             }
 
@@ -521,8 +521,14 @@ pub trait HasTyCtxt<'tcx>: HasDataLayout {
     fn tcx(&self) -> TyCtxt<'tcx>;
 }
 
-pub trait HasParamEnv<'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx>;
+pub trait HasTypingEnv<'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx>;
+
+    /// FIXME(#132279): This method should not be used as in the future
+    /// everything should take a `TypingEnv` instead. Remove it as that point.
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.typing_env().param_env
+    }
 }
 
 impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
@@ -577,9 +583,9 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
     }
 }
 
-impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
+impl<'tcx> HasTypingEnv<'tcx> for LayoutCx<'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
     }
 }
 
@@ -646,7 +652,7 @@ pub type TyAndLayout<'tcx> = rustc_abi::TyAndLayout<'tcx, Ty<'tcx>>;
 
 /// Trait for contexts that want to be able to compute layouts of types.
 /// This automatically gives access to `LayoutOf`, through a blanket `impl`.
-pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
+pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> {
     /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
     /// returned from `layout_of` (see also `handle_layout_err`).
     type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>> = TyAndLayout<'tcx>;
@@ -692,7 +698,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
         let tcx = self.tcx().at(span);
 
         MaybeResult::from(
-            tcx.layout_of(self.param_env().and(ty))
+            tcx.layout_of(self.typing_env().as_query_input(ty))
                 .map_err(|err| self.handle_layout_err(*err, span, ty)),
         )
     }
@@ -716,7 +722,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
 
 impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
 where
-    C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
+    C: HasTyCtxt<'tcx> + HasTypingEnv<'tcx>,
 {
     fn ty_and_layout_for_variant(
         this: TyAndLayout<'tcx>,
@@ -736,10 +742,10 @@ where
 
             Variants::Single { index } => {
                 let tcx = cx.tcx();
-                let param_env = cx.param_env();
+                let typing_env = cx.typing_env();
 
                 // Deny calling for_variant more than once for non-Single enums.
-                if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) {
+                if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) {
                     assert_eq!(original_layout.variants, Variants::Single { index });
                 }
 
@@ -780,7 +786,7 @@ where
 
         fn field_ty_or_layout<'tcx>(
             this: TyAndLayout<'tcx>,
-            cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
+            cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>),
             i: usize,
         ) -> TyMaybeWithLayout<'tcx> {
             let tcx = cx.tcx();
@@ -823,12 +829,13 @@ where
                             Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil)
                         };
 
-                        // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
-                        // the `Result` should always work because the type is
-                        // always either `*mut ()` or `&'static mut ()`.
+                        // NOTE: using an fully monomorphized typing env and `unwrap`-ing
+                        // the `Result` should always work because the type is always either
+                        // `*mut ()` or `&'static mut ()`.
+                        let typing_env = ty::TypingEnv::fully_monomorphized();
                         return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
                             ty: this.ty,
-                            ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+                            ..tcx.layout_of(typing_env.as_query_input(unit_ptr_ty)).unwrap()
                         });
                     }
 
@@ -848,7 +855,7 @@ where
                         && !pointee.references_error()
                     {
                         let metadata = tcx.normalize_erasing_regions(
-                            cx.param_env(),
+                            cx.typing_env(),
                             Ty::new_projection(tcx, metadata_def_id, [pointee]),
                         );
 
@@ -865,7 +872,7 @@ where
                             metadata
                         }
                     } else {
-                        match tcx.struct_tail_for_codegen(pointee, cx.param_env()).kind() {
+                        match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() {
                             ty::Slice(_) | ty::Str => tcx.types.usize,
                             ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
                             _ => bug!("TyAndLayout::field({:?}): not applicable", this),
@@ -953,7 +960,7 @@ where
 
         match field_ty_or_layout(this, cx, i) {
             TyMaybeWithLayout::Ty(field_ty) => {
-                cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
+                cx.tcx().layout_of(cx.typing_env().as_query_input(field_ty)).unwrap_or_else(|e| {
                     bug!(
                         "failed to get layout for `{field_ty}`: {e:?},\n\
                          despite it being a field (#{i}) of an existing layout: {this:#?}",
@@ -972,18 +979,18 @@ where
         offset: Size,
     ) -> Option<PointeeInfo> {
         let tcx = cx.tcx();
-        let param_env = cx.param_env();
+        let typing_env = cx.typing_env();
 
         let pointee_info = match *this.ty.kind() {
             ty::RawPtr(p_ty, _) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(p_ty)).ok().map(|layout| PointeeInfo {
+                tcx.layout_of(typing_env.as_query_input(p_ty)).ok().map(|layout| PointeeInfo {
                     size: layout.size,
                     align: layout.align.abi,
                     safe: None,
                 })
             }
             ty::FnPtr(..) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(this.ty)).ok().map(|layout| PointeeInfo {
+                tcx.layout_of(typing_env.as_query_input(this.ty)).ok().map(|layout| PointeeInfo {
                     size: layout.size,
                     align: layout.align.abi,
                     safe: None,
@@ -995,15 +1002,15 @@ where
                 // attributes in LLVM have compile-time cost even in unoptimized builds).
                 let optimize = tcx.sess.opts.optimize != OptLevel::No;
                 let kind = match mt {
-                    hir::Mutability::Not => PointerKind::SharedRef {
-                        frozen: optimize && ty.is_freeze(tcx, cx.param_env()),
-                    },
-                    hir::Mutability::Mut => PointerKind::MutableRef {
-                        unpin: optimize && ty.is_unpin(tcx, cx.param_env()),
-                    },
+                    hir::Mutability::Not => {
+                        PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) }
+                    }
+                    hir::Mutability::Mut => {
+                        PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) }
+                    }
                 };
 
-                tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
+                tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo {
                     size: layout.size,
                     align: layout.align.abi,
                     safe: Some(kind),
@@ -1093,7 +1100,7 @@ where
                         debug_assert!(pointee.safe.is_none());
                         let optimize = tcx.sess.opts.optimize != OptLevel::No;
                         pointee.safe = Some(PointerKind::Box {
-                            unpin: optimize && boxed_ty.is_unpin(tcx, cx.param_env()),
+                            unpin: optimize && boxed_ty.is_unpin(tcx, typing_env),
                             global: this.ty.is_box_global(tcx),
                         });
                     }
@@ -1304,9 +1311,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
         let span = self.layout_tcx_at_span();
         let tcx = self.tcx().at(span);
 
-        MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
-            |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
-        ))
+        MaybeResult::from(
+            tcx.fn_abi_of_fn_ptr(self.typing_env().as_query_input((sig, extra_args))).map_err(
+                |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
+            ),
+        )
     }
 
     /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
@@ -1326,17 +1335,19 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
         let tcx = self.tcx().at(span);
 
         MaybeResult::from(
-            tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
-                // HACK(eddyb) at least for definitions of/calls to `Instance`s,
-                // we can get some kind of span even if one wasn't provided.
-                // However, we don't do this early in order to avoid calling
-                // `def_span` unconditionally (which may have a perf penalty).
-                let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
-                self.handle_fn_abi_err(*err, span, FnAbiRequest::OfInstance {
-                    instance,
-                    extra_args,
-                })
-            }),
+            tcx.fn_abi_of_instance(self.typing_env().as_query_input((instance, extra_args)))
+                .map_err(|err| {
+                    // HACK(eddyb) at least for definitions of/calls to `Instance`s,
+                    // we can get some kind of span even if one wasn't provided.
+                    // However, we don't do this early in order to avoid calling
+                    // `def_span` unconditionally (which may have a perf penalty).
+                    let span =
+                        if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
+                    self.handle_fn_abi_err(*err, span, FnAbiRequest::OfInstance {
+                        instance,
+                        extra_args,
+                    })
+                }),
         )
     }
 }
@@ -1346,14 +1357,14 @@ impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
 impl<'tcx> TyCtxt<'tcx> {
     pub fn offset_of_subfield<I>(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         mut layout: TyAndLayout<'tcx>,
         indices: I,
     ) -> Size
     where
         I: Iterator<Item = (VariantIdx, FieldIdx)>,
     {
-        let cx = LayoutCx::new(self, param_env);
+        let cx = LayoutCx::new(self, typing_env);
         let mut offset = Size::ZERO;
 
         for (variant, field) in indices {
@@ -1363,7 +1374,7 @@ impl<'tcx> TyCtxt<'tcx> {
             layout = layout.field(&cx, index);
             if !layout.is_sized() {
                 // If it is not sized, then the tail must still have at least a known static alignment.
-                let tail = self.struct_tail_for_codegen(layout.ty, param_env);
+                let tail = self.struct_tail_for_codegen(layout.ty, typing_env);
                 if !matches!(tail.kind(), ty::Slice(..)) {
                     bug!(
                         "offset of not-statically-aligned field (type {:?}) cannot be computed statically",
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7fda0662a34..2bc055453a4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -62,7 +62,7 @@ pub use self::closure::{
     place_to_string_for_capture,
 };
 pub use self::consts::{
-    Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree,
+    Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
 };
 pub use self::context::{
     CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
@@ -103,7 +103,7 @@ use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
 use crate::metadata::ModChild;
 use crate::middle::privacy::EffectiveVisibilities;
 use crate::mir::{Body, CoroutineLayout};
-use crate::query::Providers;
+use crate::query::{IntoQueryParam, Providers};
 use crate::traits::{self, Reveal};
 use crate::ty;
 pub use crate::ty::diagnostics::*;
@@ -1122,6 +1122,98 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
     }
 }
 
+/// The environment in which to do trait solving.
+///
+/// Most of the time you only need to care about the `ParamEnv`
+/// as the `TypingMode` is simply stored in the `InferCtxt`.
+///
+/// However, there are some places which rely on trait solving
+/// without using an `InferCtxt` themselves. For these to be
+/// able to use the trait system they have to be able to initialize
+/// such an `InferCtxt` with the right `typing_mode`, so they need
+/// to track both.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(TypeVisitable, TypeFoldable)]
+pub struct TypingEnv<'tcx> {
+    pub typing_mode: TypingMode<'tcx>,
+    pub param_env: ParamEnv<'tcx>,
+}
+
+impl<'tcx> TypingEnv<'tcx> {
+    /// Create a typing environment with no where-clauses in scope
+    /// where all opaque types and default associated items are revealed.
+    ///
+    /// This is only suitable for monomorphized, post-typeck environments.
+    /// Do not use this for MIR optimizations, as even though they also
+    /// use `TypingMode::PostAnalysis`, they may still have where-clauses
+    /// in scope.
+    pub fn fully_monomorphized() -> TypingEnv<'tcx> {
+        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::reveal_all() }
+    }
+
+    /// Create a typing environment for use during analysis outside of a body.
+    ///
+    /// Using a typing environment inside of bodies is not supported as the body
+    /// may define opaque types. In this case the used functions have to be
+    /// converted to use proper canonical inputs instead.
+    pub fn non_body_analysis(
+        tcx: TyCtxt<'tcx>,
+        def_id: impl IntoQueryParam<DefId>,
+    ) -> TypingEnv<'tcx> {
+        TypingEnv { typing_mode: TypingMode::non_body_analysis(), param_env: tcx.param_env(def_id) }
+    }
+
+    pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
+        TypingEnv {
+            typing_mode: TypingMode::PostAnalysis,
+            param_env: tcx.param_env_reveal_all_normalized(def_id),
+        }
+    }
+
+    /// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all
+    /// opaque types in the `param_env`.
+    pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
+        let TypingEnv { typing_mode: _, param_env } = self;
+        let param_env = param_env.with_reveal_all_normalized(tcx);
+        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
+    }
+
+    /// Combine this typing environment with the given `value` to be used by
+    /// not (yet) canonicalized queries. This only works if the value does not
+    /// contain anything local to some `InferCtxt`, i.e. inference variables or
+    /// placeholders.
+    pub fn as_query_input<T>(self, value: T) -> PseudoCanonicalInput<'tcx, T>
+    where
+        T: TypeVisitable<TyCtxt<'tcx>>,
+    {
+        // FIXME(#132279): We should assert that the value does not contain any placeholders
+        // as these placeholders are also local to the current inference context. However, we
+        // currently use pseudo-canonical queries in the trait solver which replaces params with
+        // placeholders. We should also simply not use pseudo-canonical queries in the trait
+        // solver, at which point we can readd this assert. As of writing this comment, this is
+        // only used by `fn layout_is_pointer_like` when calling `layout_of`.
+        //
+        // debug_assert!(!value.has_placeholders());
+        PseudoCanonicalInput { typing_env: self, value }
+    }
+}
+
+/// Similar to `CanonicalInput`, this carries the `typing_mode` and the environment
+/// necessary to do any kind of trait solving inside of nested queries.
+///
+/// Unlike proper canonicalization, this requires the `param_env` and the `value` to not
+/// contain anything local to the `infcx` of the caller, so we don't actually canonicalize
+/// anything.
+///
+/// This should be created by using `infcx.pseudo_canonicalize_query(param_env, value)`
+/// or by using `typing_env.as_query_input(value)`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable, TypeVisitable, TypeFoldable)]
+pub struct PseudoCanonicalInput<'tcx, T> {
+    pub typing_env: TypingEnv<'tcx>,
+    pub value: T,
+}
+
 #[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
 pub struct Destructor {
     /// The `DefId` of the destructor method
@@ -2018,7 +2110,13 @@ impl<'tcx> TyCtxt<'tcx> {
                     _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
                 }
             }
-            DefKind::Closure | DefKind::OpaqueTy => {
+            DefKind::OpaqueTy => match self.opaque_ty_origin(def_id) {
+                hir::OpaqueTyOrigin::FnReturn { parent, .. } => self.is_conditionally_const(parent),
+                hir::OpaqueTyOrigin::AsyncFn { .. } => false,
+                // FIXME(const_trait_impl): ATPITs could be conditionally const?
+                hir::OpaqueTyOrigin::TyAlias { .. } => false,
+            },
+            DefKind::Closure => {
                 // Closures and RPITs will eventually have const conditions
                 // for `~const` bounds.
                 false
@@ -2150,7 +2248,6 @@ pub fn provide(providers: &mut Providers) {
         incoherent_impls: trait_def::incoherent_impls_provider,
         trait_impls_in_crate: trait_def::trait_impls_in_crate_provider,
         traits: trait_def::traits_provider,
-        const_param_default: consts::const_param_default,
         vtable_allocation: vtable::vtable_allocation_provider,
         ..*providers
     };
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index e51d2201922..f611b69905c 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -35,16 +35,16 @@ impl<'tcx> TyCtxt<'tcx> {
     ///
     /// This should only be used outside of type inference. For example,
     /// it assumes that normalization will succeed.
-    #[tracing::instrument(level = "debug", skip(self, param_env), ret)]
-    pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
+    #[tracing::instrument(level = "debug", skip(self, typing_env), ret)]
+    pub fn normalize_erasing_regions<T>(self, typing_env: ty::TypingEnv<'tcx>, value: T) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         debug!(
-            "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+            "normalize_erasing_regions::<{}>(value={:?}, typing_env={:?})",
             std::any::type_name::<T>(),
             value,
-            param_env,
+            typing_env,
         );
 
         // Erase first before we do the real query -- this keeps the
@@ -55,7 +55,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if !value.has_aliases() {
             value
         } else {
-            value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+            value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, typing_env })
         }
     }
 
@@ -66,17 +66,17 @@ impl<'tcx> TyCtxt<'tcx> {
     /// succeeds.
     pub fn try_normalize_erasing_regions<T>(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         value: T,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         debug!(
-            "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+            "try_normalize_erasing_regions::<{}>(value={:?}, typing_env={:?})",
             std::any::type_name::<T>(),
             value,
-            param_env,
+            typing_env,
         );
 
         // Erase first before we do the real query -- this keeps the
@@ -87,7 +87,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if !value.has_aliases() {
             Ok(value)
         } else {
-            let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
+            let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, typing_env);
             value.try_fold_with(&mut folder)
         }
     }
@@ -103,17 +103,17 @@ impl<'tcx> TyCtxt<'tcx> {
     // FIXME(@lcnr): This method should not be necessary, we now normalize
     // inside of binders. We should be able to only use
     // `tcx.instantiate_bound_regions_with_erased`.
-    #[tracing::instrument(level = "debug", skip(self, param_env))]
+    #[tracing::instrument(level = "debug", skip(self, typing_env))]
     pub fn normalize_erasing_late_bound_regions<T>(
         self,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         value: ty::Binder<'tcx, T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         let value = self.instantiate_bound_regions_with_erased(value);
-        self.normalize_erasing_regions(param_env, value)
+        self.normalize_erasing_regions(typing_env, value)
     }
 
     /// Monomorphizes a type from the AST by first applying the
@@ -125,14 +125,14 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn instantiate_and_normalize_erasing_regions<T>(
         self,
         param_args: GenericArgsRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         value: EarlyBinder<'tcx, T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         let instantiated = value.instantiate(self, param_args);
-        self.normalize_erasing_regions(param_env, instantiated)
+        self.normalize_erasing_regions(typing_env, instantiated)
     }
 
     /// Monomorphizes a type from the AST by first applying the
@@ -143,20 +143,20 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn try_instantiate_and_normalize_erasing_regions<T>(
         self,
         param_args: GenericArgsRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         value: EarlyBinder<'tcx, T>,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         let instantiated = value.instantiate(self, param_args);
-        self.try_normalize_erasing_regions(param_env, instantiated)
+        self.try_normalize_erasing_regions(typing_env, instantiated)
     }
 }
 
 struct NormalizeAfterErasingRegionsFolder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
@@ -164,8 +164,7 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
         &self,
         arg: ty::GenericArg<'tcx>,
     ) -> ty::GenericArg<'tcx> {
-        let arg = self.param_env.and(arg);
-
+        let arg = self.typing_env.as_query_input(arg);
         self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
             "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
             arg.value
@@ -189,12 +188,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for NormalizeAfterErasingRegionsFolder<'tcx>
 
 struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
-        TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
+    fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self {
+        TryNormalizeAfterErasingRegionsFolder { tcx, typing_env }
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -202,10 +201,8 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
         &self,
         arg: ty::GenericArg<'tcx>,
     ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
-        let arg = self.param_env.and(arg);
-        debug!(?arg);
-
-        self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
+        let input = self.typing_env.as_query_input(arg);
+        self.tcx.try_normalize_generic_arg_after_erasing_regions(input)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index 37dcf7c0d64..57c2d7623d2 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -18,15 +18,17 @@ impl RvalueScopes {
     }
 
     /// Returns the scope when the temp created by `expr_id` will be cleaned up.
+    /// It also emits a lint on potential backwards incompatible change to the temporary scope
+    /// which is *for now* always shortening.
     pub fn temporary_scope(
         &self,
         region_scope_tree: &ScopeTree,
         expr_id: hir::ItemLocalId,
-    ) -> Option<Scope> {
+    ) -> (Option<Scope>, Option<Scope>) {
         // Check for a designated rvalue scope.
         if let Some(&s) = self.map.get(&expr_id) {
             debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
-            return s;
+            return (s, None);
         }
 
         // Otherwise, locate the innermost terminating scope
@@ -34,27 +36,40 @@ impl RvalueScopes {
         // have an enclosing scope, hence no scope will be
         // returned.
         let mut id = Scope { id: expr_id, data: ScopeData::Node };
+        let mut backwards_incompatible = None;
 
         while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) {
             match p.data {
                 ScopeData::Destruction => {
                     debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
-                    return Some(id);
+                    return (Some(id), backwards_incompatible);
                 }
                 ScopeData::IfThenRescope => {
                     debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]");
-                    return Some(p);
+                    return (Some(p), backwards_incompatible);
                 }
                 ScopeData::Node
                 | ScopeData::CallSite
                 | ScopeData::Arguments
                 | ScopeData::IfThen
-                | ScopeData::Remainder(_) => id = p,
+                | ScopeData::Remainder(_) => {
+                    // If we haven't already passed through a backwards-incompatible node,
+                    // then check if we are passing through one now and record it if so.
+                    // This is for now only working for cases where a temporary lifetime is
+                    // *shortened*.
+                    if backwards_incompatible.is_none() {
+                        backwards_incompatible = region_scope_tree
+                            .backwards_incompatible_scope
+                            .get(&p.item_local_id())
+                            .copied();
+                    }
+                    id = p
+                }
             }
         }
 
         debug!("temporary_scope({expr_id:?}) = None");
-        None
+        (None, backwards_incompatible)
     }
 
     /// Make an association between a sub-expression and an extended lifetime
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 3c6e34160f4..20c3f84bb4d 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -18,6 +18,7 @@ use rustc_span::sym;
 use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
 
+use super::TypingEnv;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::query::Providers;
 use crate::ty::layout::{FloatExt, IntegerExt};
@@ -177,9 +178,13 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Should only be called if `ty` has no inference variables and does not
     /// need its lifetimes preserved (e.g. as part of codegen); otherwise
     /// normalization attempt may cause compiler bugs.
-    pub fn struct_tail_for_codegen(self, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
+    pub fn struct_tail_for_codegen(
+        self,
+        ty: Ty<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+    ) -> Ty<'tcx> {
         let tcx = self;
-        tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
+        tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(typing_env, ty), || {})
     }
 
     /// Returns the deeply last field of nested structures, or the same type if
@@ -271,11 +276,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         source: Ty<'tcx>,
         target: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> (Ty<'tcx>, Ty<'tcx>) {
         let tcx = self;
         tcx.struct_lockstep_tails_raw(source, target, |ty| {
-            tcx.normalize_erasing_regions(param_env, ty)
+            tcx.normalize_erasing_regions(typing_env, ty)
         })
     }
 
@@ -420,10 +425,10 @@ impl<'tcx> TyCtxt<'tcx> {
 
         // Async drop glue morphology is an internal detail, so reveal_all probably
         // should be fine
-        let param_env = ty::ParamEnv::reveal_all();
-        if ty.needs_async_drop(self, param_env) {
+        let typing_env = ty::TypingEnv::fully_monomorphized();
+        if ty.needs_async_drop(self, typing_env) {
             AsyncDropGlueMorphology::Custom
-        } else if ty.needs_drop(self, param_env) {
+        } else if ty.needs_drop(self, typing_env) {
             AsyncDropGlueMorphology::DeferredDropInPlace
         } else {
             AsyncDropGlueMorphology::Noop
@@ -683,12 +688,10 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Get the type of the pointer to the static that we use in MIR.
-    pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
+    pub fn static_ptr_ty(self, def_id: DefId, typing_env: ty::TypingEnv<'tcx>) -> Ty<'tcx> {
         // Make sure that any constants in the static's type are evaluated.
-        let static_ty = self.normalize_erasing_regions(
-            ty::ParamEnv::empty(),
-            self.type_of(def_id).instantiate_identity(),
-        );
+        let static_ty =
+            self.normalize_erasing_regions(typing_env, self.type_of(def_id).instantiate_identity());
 
         // Make sure that accesses to unsafe statics end up using raw pointers.
         // For thread-locals, this needs to be kept in sync with `Rvalue::ty`.
@@ -1157,15 +1160,17 @@ impl<'tcx> Ty<'tcx> {
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
     pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
+        let typing_env = TypingEnv::fully_monomorphized();
         self.numeric_min_and_max_as_bits(tcx)
-            .map(|(_, max)| ty::Const::from_bits(tcx, max, ty::ParamEnv::empty().and(self)))
+            .map(|(_, max)| ty::Const::from_bits(tcx, max, typing_env, self))
     }
 
     /// Returns the minimum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
     pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
+        let typing_env = TypingEnv::fully_monomorphized();
         self.numeric_min_and_max_as_bits(tcx)
-            .map(|(min, _)| ty::Const::from_bits(tcx, min, ty::ParamEnv::empty().and(self)))
+            .map(|(min, _)| ty::Const::from_bits(tcx, min, typing_env, self))
     }
 
     /// Checks whether values of this type `T` are *moved* or *copied*
@@ -1175,8 +1180,12 @@ impl<'tcx> Ty<'tcx> {
     /// does copies even when the type actually doesn't satisfy the
     /// full requirements for the `Copy` trait (cc #29149) -- this
     /// winds up being reported as an error during NLL borrow check.
-    pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self))
+    pub fn is_copy_modulo_regions(
+        self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+    ) -> bool {
+        self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(typing_env.as_query_input(self))
     }
 
     /// Checks whether values of this type `T` have a size known at
@@ -1185,8 +1194,8 @@ impl<'tcx> Ty<'tcx> {
     /// over-approximation in generic contexts, where one can have
     /// strange rules like `<T as Foo<'static>>::Bar: Sized` that
     /// actually carry lifetime requirements.
-    pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self))
+    pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
+        self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self))
     }
 
     /// Checks whether values of this type `T` implement the `Freeze`
@@ -1196,8 +1205,8 @@ impl<'tcx> Ty<'tcx> {
     /// optimization as well as the rules around static values. Note
     /// that the `Freeze` trait is not exposed to end users and is
     /// effectively an implementation detail.
-    pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self))
+    pub fn is_freeze(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
+        self.is_trivially_freeze() || tcx.is_freeze_raw(typing_env.as_query_input(self))
     }
 
     /// Fast path helper for testing if a type is `Freeze`.
@@ -1236,8 +1245,8 @@ impl<'tcx> Ty<'tcx> {
     }
 
     /// Checks whether values of this type `T` implement the `Unpin` trait.
-    pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self))
+    pub fn is_unpin(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
+        self.is_trivially_unpin() || tcx.is_unpin_raw(typing_env.as_query_input(self))
     }
 
     /// Fast path helper for testing if a type is `Unpin`.
@@ -1345,7 +1354,7 @@ impl<'tcx> Ty<'tcx> {
     ///
     /// Note that this method is used to check eligible types in unions.
     #[inline]
-    pub fn needs_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn needs_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
         // Avoid querying in simple cases.
         match needs_drop_components(tcx, self) {
             Err(AlwaysRequiresDrop) => true,
@@ -1359,14 +1368,13 @@ impl<'tcx> Ty<'tcx> {
                 };
 
                 // This doesn't depend on regions, so try to minimize distinct
-                // query keys used.
-                // If normalization fails, we just use `query_ty`.
-                debug_assert!(!param_env.has_infer());
+                // query keys used. If normalization fails, we just use `query_ty`.
+                debug_assert!(!typing_env.param_env.has_infer());
                 let query_ty = tcx
-                    .try_normalize_erasing_regions(param_env, query_ty)
+                    .try_normalize_erasing_regions(typing_env, query_ty)
                     .unwrap_or_else(|_| tcx.erase_regions(query_ty));
 
-                tcx.needs_drop_raw(param_env.and(query_ty))
+                tcx.needs_drop_raw(typing_env.as_query_input(query_ty))
             }
         }
     }
@@ -1385,7 +1393,7 @@ impl<'tcx> Ty<'tcx> {
     // FIXME(zetanumbers): Note that this method is used to check eligible types
     // in unions.
     #[inline]
-    pub fn needs_async_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn needs_async_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
         // Avoid querying in simple cases.
         match needs_drop_components(tcx, self) {
             Err(AlwaysRequiresDrop) => true,
@@ -1401,12 +1409,12 @@ impl<'tcx> Ty<'tcx> {
                 // This doesn't depend on regions, so try to minimize distinct
                 // query keys used.
                 // If normalization fails, we just use `query_ty`.
-                debug_assert!(!param_env.has_infer());
+                debug_assert!(!typing_env.has_infer());
                 let query_ty = tcx
-                    .try_normalize_erasing_regions(param_env, query_ty)
+                    .try_normalize_erasing_regions(typing_env, query_ty)
                     .unwrap_or_else(|_| tcx.erase_regions(query_ty));
 
-                tcx.needs_async_drop_raw(param_env.and(query_ty))
+                tcx.needs_async_drop_raw(typing_env.as_query_input(query_ty))
             }
         }
     }
@@ -1420,7 +1428,7 @@ impl<'tcx> Ty<'tcx> {
     /// Note that this method is used to check for change in drop order for
     /// 2229 drop reorder migration analysis.
     #[inline]
-    pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
         // Avoid querying in simple cases.
         match needs_drop_components(tcx, self) {
             Err(AlwaysRequiresDrop) => true,
@@ -1443,8 +1451,8 @@ impl<'tcx> Ty<'tcx> {
 
                 // This doesn't depend on regions, so try to minimize distinct
                 // query keys used.
-                let erased = tcx.normalize_erasing_regions(param_env, query_ty);
-                tcx.has_significant_drop_raw(param_env.and(erased))
+                let erased = tcx.normalize_erasing_regions(typing_env, query_ty);
+                tcx.has_significant_drop_raw(typing_env.as_query_input(erased))
             }
         }
     }
@@ -1793,7 +1801,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
         Some(ty::IntrinsicDef {
             name: tcx.item_name(def_id.into()),
             must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
-            const_stable: tcx.has_attr(def_id, sym::rustc_const_stable_intrinsic),
+            const_stable: tcx.has_attr(def_id, sym::rustc_intrinsic_const_stable_indirect),
         })
     } else {
         None
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 963fa12a8c7..e5eeb23be25 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -97,7 +97,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
     assert!(vtable_entries.len() >= vtable_min_entries(tcx, poly_trait_ref));
 
     let layout = tcx
-        .layout_of(ty::ParamEnv::reveal_all().and(ty))
+        .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
         .expect("failed to build vtable representation");
     assert!(layout.is_sized(), "can't create a vtable for an unsized type");
     let size = layout.size.bytes();
@@ -117,7 +117,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
         let idx: u64 = u64::try_from(idx).unwrap();
         let scalar = match entry {
             VtblEntry::MetadataDropInPlace => {
-                if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
+                if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) {
                     let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
                     let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
                     let fn_ptr = Pointer::from(fn_alloc_id);
diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs
index ed27a880562..acfb78b3f6e 100644
--- a/compiler/rustc_middle/src/util/call_kind.rs
+++ b/compiler/rustc_middle/src/util/call_kind.rs
@@ -8,7 +8,7 @@ use rustc_span::symbol::Ident;
 use rustc_span::{DesugaringKind, Span, sym};
 use tracing::debug;
 
-use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, ParamEnv, Ty, TyCtxt};
+use crate::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum CallDesugaringKind {
@@ -62,7 +62,7 @@ pub enum CallKind<'tcx> {
 
 pub fn call_kind<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     method_did: DefId,
     method_args: GenericArgsRef<'tcx>,
     fn_call_span: Span,
@@ -98,10 +98,10 @@ pub fn call_kind<'tcx>(
         Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) })
     } else if is_deref {
         let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
-            Instance::try_resolve(tcx, param_env, deref_target, method_args).transpose()
+            Instance::try_resolve(tcx, typing_env, deref_target, method_args).transpose()
         });
         if let Some(Ok(instance)) = deref_target {
-            let deref_target_ty = instance.ty(tcx, param_env);
+            let deref_target_ty = instance.ty(tcx, typing_env);
             Some(CallKind::DerefCoercion {
                 deref_target: tcx.def_span(instance.def_id()),
                 deref_target_ty,
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 4815db47b16..e809c9a23f3 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -25,7 +25,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 
 mod parse;
@@ -77,7 +77,7 @@ pub(super) fn build_custom_mir<'tcx>(
 
     let mut pctxt = ParseCtxt {
         tcx,
-        param_env: tcx.param_env(did),
+        typing_env: body.typing_env(tcx),
         thir,
         source_scope: OUTERMOST_SOURCE_SCOPE,
         body: &mut body,
@@ -136,7 +136,7 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
 
 struct ParseCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     thir: &'a Thir<'tcx>,
     source_scope: SourceScope,
     body: &'a mut Body<'tcx>,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 07964e304b9..c3e9bd302de 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,14 +144,22 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let PatKind::Constant { value } = arm.pattern.kind else {
-                return Err(ParseError {
-                    span: arm.pattern.span,
-                    item_description: format!("{:?}", arm.pattern.kind),
-                    expected: "constant pattern".to_string(),
-                });
+            let value = match arm.pattern.kind {
+                PatKind::Constant { value } => value,
+                PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
+                    if let PatKind::Constant { value } = subpattern.kind =>
+                {
+                    value
+                }
+                _ => {
+                    return Err(ParseError {
+                        span: arm.pattern.span,
+                        item_description: format!("{:?}", arm.pattern.kind),
+                        expected: "constant pattern".to_string(),
+                    });
+                }
             };
-            values.push(value.eval_bits(self.tcx, self.param_env));
+            values.push(value.eval_bits(self.tcx, self.typing_env));
             targets.push(self.parse_block(arm.body)?);
         }
 
@@ -385,7 +393,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
             | ExprKind::NonHirLiteral { .. }
             | ExprKind::ConstBlock { .. } => Ok({
                 let value = as_constant_inner(expr, |_| None, self.tcx);
-                value.const_.eval_bits(self.tcx, self.param_env)
+                value.const_.eval_bits(self.tcx, self.typing_env)
             }),
         )
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 3f2e3b956fc..640408cb9c8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -114,8 +114,7 @@ fn lit_to_mir_constant<'tcx>(
 ) -> Result<Const<'tcx>, LitToConstError> {
     let LitToConstInput { lit, ty, neg } = lit_input;
     let trunc = |n| {
-        let param_ty = ty::ParamEnv::reveal_all().and(ty);
-        let width = match tcx.layout_of(param_ty) {
+        let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
             Ok(layout) => layout.size,
             Err(_) => {
                 tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit))
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 112eac32264..0cab853196b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -1,6 +1,5 @@
 //! See docs in build/expr/mod.rs
 
-use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use tracing::{debug, instrument};
@@ -9,6 +8,12 @@ use crate::build::expr::category::Category;
 use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Construct a temporary lifetime restricted to just the local scope
+    pub(crate) fn local_temp_lifetime(&self) -> TempLifetime {
+        let local_scope = self.local_scope();
+        TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None }
+    }
+
     /// Returns an operand suitable for use until the end of the current
     /// scope expression.
     ///
@@ -21,8 +26,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block: BasicBlock,
         expr_id: ExprId,
     ) -> BlockAnd<Operand<'tcx>> {
-        let local_scope = self.local_scope();
-        self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe)
+        self.as_operand(
+            block,
+            self.local_temp_lifetime(),
+            expr_id,
+            LocalInfo::Boring,
+            NeedsTemporary::Maybe,
+        )
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -80,8 +90,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block: BasicBlock,
         expr: ExprId,
     ) -> BlockAnd<Operand<'tcx>> {
-        let local_scope = self.local_scope();
-        self.as_call_operand(block, Some(local_scope), expr)
+        self.as_call_operand(block, self.local_temp_lifetime(), expr)
     }
 
     /// Compile `expr` into a value that can be used as an operand.
@@ -102,7 +111,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn as_operand(
         &mut self,
         mut block: BasicBlock,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         expr_id: ExprId,
         local_info: LocalInfo<'tcx>,
         needs_temporary: NeedsTemporary,
@@ -123,7 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match category {
             Category::Constant
                 if matches!(needs_temporary, NeedsTemporary::No)
-                    || !expr.ty.needs_drop(this.tcx, this.param_env) =>
+                    || !expr.ty.needs_drop(this.tcx, this.typing_env()) =>
             {
                 let constant = this.as_constant(expr);
                 block.and(Operand::Constant(Box::new(constant)))
@@ -146,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn as_call_operand(
         &mut self,
         mut block: BasicBlock,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         expr_id: ExprId,
     ) -> BlockAnd<Operand<'tcx>> {
         let this = self;
@@ -165,11 +174,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         if tcx.features().unsized_fn_params() {
             let ty = expr.ty;
-            let param_env = this.param_env;
-
-            if !ty.is_sized(tcx, param_env) {
+            if !ty.is_sized(tcx, this.typing_env()) {
                 // !sized means !copy, so this is an unsized move
-                assert!(!ty.is_copy_modulo_regions(tcx, param_env));
+                assert!(!ty.is_copy_modulo_regions(tcx, this.typing_env()));
 
                 // As described above, detect the case where we are passing a value of unsized
                 // type, and that value is coming from the deref of a box.
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 9f6e0735b48..6ce88cdc39d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -6,7 +6,6 @@ use std::iter;
 use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind};
-use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -598,7 +597,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         index: ExprId,
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
-        temp_lifetime: Option<region::Scope>,
+        temp_lifetime: TempLifetime,
         expr_span: Span,
         source_info: SourceInfo,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 1985dd3fca0..3f89e337781 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -33,14 +33,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr_id: ExprId,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let local_scope = self.local_scope();
-        self.as_rvalue(block, Some(local_scope), expr_id)
+        self.as_rvalue(
+            block,
+            TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None },
+            expr_id,
+        )
     }
 
     /// Compile `expr`, yielding an rvalue.
     pub(crate) fn as_rvalue(
         &mut self,
         mut block: BasicBlock,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         expr_id: ExprId,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let this = self;
@@ -171,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     source_info,
                     kind: StatementKind::StorageLive(result),
                 });
-                if let Some(scope) = scope {
+                if let Some(scope) = scope.temp_lifetime {
                     // schedule a shallow free of that memory, lest we unwind:
                     this.schedule_drop_storage_and_value(expr_span, scope, result);
                 }
@@ -197,7 +201,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 {
                     let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
                     let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
-                    let layout = this.tcx.layout_of(this.param_env.and(source_expr.ty));
+                    let layout =
+                        this.tcx.layout_of(this.typing_env().as_query_input(source_expr.ty));
                     let discr = this.temp(discr_ty, source_expr.span);
                     this.cfg.push_assign(
                         block,
@@ -226,10 +231,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             if range.start <= range.end { BinOp::BitAnd } else { BinOp::BitOr };
 
                         let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
+                            // We can use `ty::TypingEnv::fully_monomorphized()`` here
+                            // as we only need it to compute the layout of a primitive.
                             let range_val = Const::from_bits(
                                 this.tcx,
                                 range,
-                                ty::ParamEnv::empty().and(unsigned_ty),
+                                ty::TypingEnv::fully_monomorphized(),
+                                unsigned_ty,
                             );
                             let lit_op = this.literal_operand(expr.span, range_val);
                             let is_bin_op = this.temp(bool_ty, expr_span);
@@ -441,7 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                         block = this.limit_capture_mutability(
                                             upvar_expr.span,
                                             upvar_expr.ty,
-                                            scope,
+                                            scope.temp_lifetime,
                                             block,
                                             arg,
                                         )
@@ -701,7 +709,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         value: ExprId,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         outer_source_info: SourceInfo,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let this = self;
@@ -812,9 +820,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     // Helper to get a `-1` value of the appropriate type
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let param_ty = ty::ParamEnv::empty().and(ty);
-        let size = self.tcx.layout_of(param_ty).unwrap().size;
-        let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
+        let typing_env = ty::TypingEnv::fully_monomorphized();
+        let size = self.tcx.layout_of(typing_env.as_query_input(ty)).unwrap().size;
+        let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), typing_env, ty);
 
         self.literal_operand(span, literal)
     }
@@ -822,10 +830,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     // Helper to get the minimum value of the appropriate type
     fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         assert!(ty.is_signed());
-        let param_ty = ty::ParamEnv::empty().and(ty);
-        let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
+        let typing_env = ty::TypingEnv::fully_monomorphized();
+        let bits = self.tcx.layout_of(typing_env.as_query_input(ty)).unwrap().size.bits();
         let n = 1 << (bits - 1);
-        let literal = Const::from_bits(self.tcx, n, param_ty);
+        let literal = Const::from_bits(self.tcx, n, typing_env, ty);
 
         self.literal_operand(span, literal)
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index b8b5e4634ed..466f67b1ba4 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -2,7 +2,6 @@
 
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::HirId;
-use rustc_middle::middle::region;
 use rustc_middle::middle::region::{Scope, ScopeData};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -17,7 +16,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn as_temp(
         &mut self,
         block: BasicBlock,
-        temp_lifetime: Option<region::Scope>,
+        temp_lifetime: TempLifetime,
         expr_id: ExprId,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
@@ -31,7 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn as_temp_inner(
         &mut self,
         mut block: BasicBlock,
-        temp_lifetime: Option<region::Scope>,
+        temp_lifetime: TempLifetime,
         expr_id: ExprId,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
@@ -47,8 +46,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         let expr_ty = expr.ty;
-        let deduplicate_temps =
-            this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime;
+        let deduplicate_temps = this.fixed_temps_scope.is_some()
+            && this.fixed_temps_scope == temp_lifetime.temp_lifetime;
         let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) {
             *temp_index
         } else {
@@ -76,7 +75,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     LocalInfo::BlockTailTemp(tail_info)
                 }
 
-                _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = temp_lifetime => {
+                _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) =
+                    temp_lifetime.temp_lifetime =>
+                {
                     LocalInfo::IfThenRescopeTemp {
                         if_then: HirId { owner: this.hir_id.owner, local_id: id },
                     }
@@ -117,7 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Anything with a shorter lifetime (e.g the `&foo()` in
                 // `bar(&foo())` or anything within a block will keep the
                 // regular drops just like runtime code.
-                if let Some(temp_lifetime) = temp_lifetime {
+                if let Some(temp_lifetime) = temp_lifetime.temp_lifetime {
                     this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage);
                 }
             }
@@ -125,10 +126,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         block = this.expr_into_dest(temp_place, block, expr_id).into_block();
 
-        if let Some(temp_lifetime) = temp_lifetime {
+        if let Some(temp_lifetime) = temp_lifetime.temp_lifetime {
             this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
         }
 
+        if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible {
+            this.schedule_backwards_incompatible_drop(expr_span, backwards_incompatible, temp);
+        }
+
         block.and(temp)
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index dc317feb20c..bebb44faba6 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -139,7 +139,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // (#66975) Source could be a const of type `!`, so has to
                 // exist in the generated MIR.
                 unpack!(
-                    block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut)
+                    block =
+                        this.as_temp(block, this.local_temp_lifetime(), source, Mutability::Mut)
                 );
 
                 // This is an optimization. If the expression was a call then we already have an
@@ -266,7 +267,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // that makes the call.
                     target: expr
                         .ty
-                        .is_inhabited_from(this.tcx, this.parent_module, this.param_env)
+                        .is_inhabited_from(
+                            this.tcx,
+                            this.parent_module,
+                            this.infcx.typing_env(this.param_env),
+                        )
                         .then_some(success),
                     call_source: if from_hir_call {
                         CallSource::Normal
@@ -317,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let is_union = adt_def.is_union();
                 let active_field_index = is_union.then(|| fields[0].name);
 
-                let scope = this.local_scope();
+                let scope = this.local_temp_lifetime();
 
                 // first process the set of fields that were provided
                 // (evaluating them in order given by user)
@@ -329,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             unpack!(
                                 block = this.as_operand(
                                     block,
-                                    Some(scope),
+                                    scope,
                                     f.expr,
                                     LocalInfo::AggregateTemp,
                                     NeedsTemporary::Maybe,
@@ -544,15 +549,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             ExprKind::Yield { value } => {
-                let scope = this.local_scope();
+                let scope = this.local_temp_lifetime();
                 let value = unpack!(
-                    block = this.as_operand(
-                        block,
-                        Some(scope),
-                        value,
-                        LocalInfo::Boring,
-                        NeedsTemporary::No
-                    )
+                    block =
+                        this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)
                 );
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(block, source_info, TerminatorKind::Yield {
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 76034c03b4b..15ee6dd014c 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -42,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 // Generate better code for things that don't need to be
                 // dropped.
-                if lhs_expr.ty.needs_drop(this.tcx, this.param_env) {
+                if lhs_expr.ty.needs_drop(this.tcx, this.typing_env()) {
                     let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
                     let lhs = unpack!(block = this.as_place(block, lhs));
                     block =
@@ -172,8 +172,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     None
                 };
 
-                let temp =
-                    unpack!(block = this.as_temp(block, statement_scope, expr_id, Mutability::Not));
+                let temp = unpack!(
+                    block = this.as_temp(
+                        block,
+                        TempLifetime {
+                            temp_lifetime: statement_scope,
+                            backwards_incompatible: None
+                        },
+                        expr_id,
+                        Mutability::Not
+                    )
+                );
 
                 if let Some(span) = adjusted_span {
                     this.local_decls[temp].source_info.span = span;
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 6df50057ee8..2815b390375 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 TestCase::Irrefutable { ascription: None, binding }
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
+                subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
+                default_irrefutable()
+            }
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
                 // Apply a type ascription for the inline constant to the value at `match_pair.place`
                 let ascription = place.map(|source| {
                     let span = pattern.span;
@@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                     })
                     .args;
                     let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def.to_def_id(),
+                        def_id,
                         ty::UserArgs { args, user_self_ty: None },
                     ));
                     let annotation = ty::CanonicalUserTypeAnnotation {
@@ -214,7 +218,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                         || !v
                             .inhabited_predicate(cx.tcx, adt_def)
                             .instantiate(cx.tcx, args)
-                            .apply_ignore_module(cx.tcx, cx.param_env)
+                            .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env))
                 }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a62d4e9d873..5791460a6b1 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -202,8 +202,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Increment the decision depth, in case we encounter boolean expressions
                 // further down.
                 this.mcdc_increment_depth_if_enabled();
-                let place =
-                    unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability));
+                let place = unpack!(
+                    block = this.as_temp(
+                        block,
+                        TempLifetime {
+                            temp_lifetime: Some(temp_scope),
+                            backwards_incompatible: None
+                        },
+                        expr_id,
+                        mutability
+                    )
+                );
                 this.mcdc_decrement_depth_if_enabled();
 
                 let operand = Operand::Move(Place::from(place));
@@ -917,7 +926,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
-            PatKind::InlineConstant { ref subpattern, .. } => {
+            PatKind::ExpandedConstant { ref subpattern, .. } => {
                 self.visit_primary_bindings(subpattern, pattern_user_ty, f)
             }
 
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 37cedd8cf5c..4f7bbc4ce3e 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -567,7 +567,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // not to add such values here.
                 let is_covering_range = |test_case: &TestCase<'_, 'tcx>| {
                     test_case.as_range().is_some_and(|range| {
-                        matches!(range.contains(value, self.tcx, self.param_env), None | Some(true))
+                        matches!(
+                            range.contains(value, self.tcx, self.typing_env()),
+                            None | Some(true)
+                        )
                     })
                 };
                 let is_conflicting_candidate = |candidate: &&mut Candidate<'_, 'tcx>| {
@@ -584,7 +587,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     None
                 } else {
                     fully_matched = true;
-                    let bits = value.eval_bits(self.tcx, self.param_env);
+                    let bits = value.eval_bits(self.tcx, self.typing_env());
                     Some(TestBranch::Constant(value, bits))
                 }
             }
@@ -596,7 +599,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 fully_matched = false;
                 let not_contained =
                     sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(
-                        |val| matches!(range.contains(val, self.tcx, self.param_env), Some(false)),
+                        |val| {
+                            matches!(range.contains(val, self.tcx, self.typing_env()), Some(false))
+                        },
                     );
 
                 not_contained.then(|| {
@@ -608,7 +613,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             (TestKind::If, TestCase::Constant { value }) => {
                 fully_matched = true;
-                let value = value.try_eval_bool(self.tcx, self.param_env).unwrap_or_else(|| {
+                let value = value.try_eval_bool(self.tcx, self.typing_env()).unwrap_or_else(|| {
                     span_bug!(test.span, "expected boolean value but got {value:?}")
                 });
                 Some(if value { TestBranch::Success } else { TestBranch::Failure })
@@ -688,7 +693,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     fully_matched = false;
                     // If the testing range does not overlap with pattern range,
                     // the pattern can be matched only if this test fails.
-                    if !test.overlaps(pat, self.tcx, self.param_env)? {
+                    if !test.overlaps(pat, self.tcx, self.typing_env())? {
                         Some(TestBranch::Failure)
                     } else {
                         None
@@ -697,7 +702,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             (TestKind::Range(range), &TestCase::Constant { value }) => {
                 fully_matched = false;
-                if !range.contains(value, self.tcx, self.param_env)? {
+                if !range.contains(value, self.tcx, self.typing_env())? {
                     // `value` is not contained in the testing range,
                     // so `value` can be matched only if this test fails.
                     Some(TestBranch::Failure)
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index 53cb99d44e8..a14dcad6573 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -32,7 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Returns a zero literal operand for the appropriate type, works for
     /// bool, char and integers.
     pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
+        let literal = Const::from_bits(self.tcx, 0, ty::TypingEnv::fully_monomorphized(), ty);
 
         self.literal_operand(span, literal)
     }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 46be2aee637..3317f3b7f8a 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -148,6 +148,10 @@ struct BlockContext(Vec<BlockFrame>);
 
 struct Builder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
+    // FIXME(@lcnr): Why does this use an `infcx`, there should be
+    // no shared type inference going on here. I feel like it would
+    // clearer to manually construct one where necessary or to provide
+    // a nice API for non-type inference trait system checks.
     infcx: InferCtxt<'tcx>,
     region_scope_tree: &'tcx region::ScopeTree,
     param_env: ty::ParamEnv<'tcx>,
@@ -230,6 +234,10 @@ struct Capture<'tcx> {
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.infcx.typing_env(self.param_env)
+    }
+
     fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
         self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
     }
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index a7e56b8f589..636e47b7ad2 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -89,7 +89,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{ExprId, LintLevel};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty};
 use rustc_session::lint::Level;
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Span};
@@ -151,6 +151,9 @@ struct DropData {
 
     /// Whether this is a value Drop or a StorageDead.
     kind: DropKind,
+
+    /// Whether this is a backwards-incompatible drop lint
+    backwards_incompatible_lint: bool,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -274,8 +277,12 @@ impl DropTree {
         // represents the block in the tree that should be jumped to once all
         // of the required drops have been performed.
         let fake_source_info = SourceInfo::outermost(DUMMY_SP);
-        let fake_data =
-            DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
+        let fake_data = DropData {
+            source_info: fake_source_info,
+            local: Local::MAX,
+            kind: DropKind::Storage,
+            backwards_incompatible_lint: false,
+        };
         let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
         Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
     }
@@ -763,7 +770,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let local =
                         place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
 
-                    Some(DropData { source_info, local, kind: DropKind::Value })
+                    Some(DropData {
+                        source_info,
+                        local,
+                        kind: DropKind::Value,
+                        backwards_incompatible_lint: false,
+                    })
                 }
                 Operand::Constant(_) => None,
             })
@@ -1010,7 +1022,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) {
         let needs_drop = match drop_kind {
             DropKind::Value => {
-                if !self.local_decls[local].ty.needs_drop(self.tcx, self.param_env) {
+                if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) {
                     return;
                 }
                 true
@@ -1019,9 +1031,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 if local.index() <= self.arg_count {
                     span_bug!(
                         span,
-                        "`schedule_drop` called with local {:?} and arg_count {}",
+                        "`schedule_drop` called with body argument {:?} \
+                        but its storage does not require a drop",
                         local,
-                        self.arg_count,
                     )
                 }
                 false
@@ -1089,6 +1101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
                     local,
                     kind: drop_kind,
+                    backwards_incompatible_lint: false,
                 });
 
                 return;
@@ -1098,6 +1111,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
     }
 
+    /// Schedule emission of a backwards incompatible drop lint hint.
+    /// Applicable only to temporary values for now.
+    pub(crate) fn schedule_backwards_incompatible_drop(
+        &mut self,
+        span: Span,
+        region_scope: region::Scope,
+        local: Local,
+    ) {
+        if !self.local_decls[local].ty.has_significant_drop(self.tcx, ty::TypingEnv {
+            typing_mode: ty::TypingMode::non_body_analysis(),
+            param_env: self.param_env,
+        }) {
+            return;
+        }
+        for scope in self.scopes.scopes.iter_mut().rev() {
+            // Since we are inserting linting MIR statement, we have to invalidate the caches
+            scope.invalidate_cache();
+            if scope.region_scope == region_scope {
+                let region_scope_span = region_scope.span(self.tcx, self.region_scope_tree);
+                let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
+
+                scope.drops.push(DropData {
+                    source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
+                    local,
+                    kind: DropKind::Value,
+                    backwards_incompatible_lint: true,
+                });
+
+                return;
+            }
+        }
+        span_bug!(
+            span,
+            "region scope {:?} not in scope to drop {:?} for linting",
+            region_scope,
+            local
+        );
+    }
+
     /// Indicates that the "local operand" stored in `local` is
     /// *moved* at some point during execution (see `local_scope` for
     /// more information about what a "local operand" is -- in short,
@@ -1378,16 +1430,25 @@ fn build_scope_drops<'tcx>(
                     continue;
                 }
 
-                unwind_drops.add_entry_point(block, unwind_to);
-
-                let next = cfg.start_new_block();
-                cfg.terminate(block, source_info, TerminatorKind::Drop {
-                    place: local.into(),
-                    target: next,
-                    unwind: UnwindAction::Continue,
-                    replace: false,
-                });
-                block = next;
+                if drop_data.backwards_incompatible_lint {
+                    cfg.push(block, Statement {
+                        source_info,
+                        kind: StatementKind::BackwardIncompatibleDropHint {
+                            place: Box::new(local.into()),
+                            reason: BackwardIncompatibleDropReason::Edition2024,
+                        },
+                    });
+                } else {
+                    unwind_drops.add_entry_point(block, unwind_to);
+                    let next = cfg.start_new_block();
+                    cfg.terminate(block, source_info, TerminatorKind::Drop {
+                        place: local.into(),
+                        target: next,
+                        unwind: UnwindAction::Continue,
+                        replace: false,
+                    });
+                    block = next;
+                }
             }
             DropKind::Storage => {
                 if storage_dead_on_unwind {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 33e194fa246..b497e54d480 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -11,7 +11,7 @@ use rustc_middle::span_bug;
 use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint::Level;
 use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -37,7 +37,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
     /// of the LHS and the span of the assignment expression.
     assignment_info: Option<Ty<'tcx>>,
     in_union_destructure: bool,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     inside_adt: bool,
     warnings: &'a mut Vec<UnusedUnsafeWarning>,
 
@@ -213,7 +213,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
                 body_target_features: self.body_target_features,
                 assignment_info: self.assignment_info,
                 in_union_destructure: false,
-                param_env: self.param_env,
+                typing_env: self.typing_env,
                 inside_adt: false,
                 warnings: self.warnings,
                 suggest_unsafe_block: self.suggest_unsafe_block,
@@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns, which we recurse on below.
                 PatKind::Or { .. } |
-                PatKind::InlineConstant { .. } |
+                PatKind::ExpandedConstant { .. } |
                 PatKind::AscribeUserType { .. } |
                 PatKind::Error(_) => {}
             }
@@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     };
                     match rm {
                         Mutability::Not => {
-                            if !ty.is_freeze(self.tcx, self.param_env) {
+                            if !ty.is_freeze(self.tcx, self.typing_env) {
                                 self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
                             }
                         }
@@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
             }
-            PatKind::InlineConstant { def, .. } => {
-                self.visit_inner_body(*def);
+            PatKind::ExpandedConstant { def_id, is_inline, .. } => {
+                if let Some(def) = def_id.as_local()
+                    && *is_inline
+                {
+                    self.visit_inner_body(def);
+                }
                 visit::walk_pat(self, pat);
             }
             _ => {
@@ -533,8 +537,45 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     self.requires_unsafe(expr.span, DerefOfRawPointer);
                 }
             }
-            ExprKind::InlineAsm { .. } => {
+            ExprKind::InlineAsm(box InlineAsmExpr {
+                asm_macro: _,
+                ref operands,
+                template: _,
+                options: _,
+                line_spans: _,
+            }) => {
                 self.requires_unsafe(expr.span, UseOfInlineAssembly);
+
+                // For inline asm, do not use `walk_expr`, since we want to handle the label block
+                // specially.
+                for op in &**operands {
+                    use rustc_middle::thir::InlineAsmOperand::*;
+                    match op {
+                        In { expr, reg: _ }
+                        | Out { expr: Some(expr), reg: _, late: _ }
+                        | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]),
+                        SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
+                            self.visit_expr(&self.thir()[*in_expr]);
+                            if let Some(out_expr) = out_expr {
+                                self.visit_expr(&self.thir()[*out_expr]);
+                            }
+                        }
+                        Out { expr: None, reg: _, late: _ }
+                        | Const { value: _, span: _ }
+                        | SymFn { value: _, span: _ }
+                        | SymStatic { def_id: _ } => {}
+                        Label { block } => {
+                            // Label blocks are safe context.
+                            // `asm!()` is forced to be wrapped inside unsafe. If there's no special
+                            // treatment, the label blocks would also always be unsafe with no way
+                            // of opting out.
+                            self.in_safety_context(SafetyContext::Safe, |this| {
+                                visit::walk_block(this, &this.thir()[*block])
+                            });
+                        }
+                    }
+                }
+                return;
             }
             ExprKind::Adt(box AdtExpr {
                 adt_def,
@@ -566,7 +607,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     && adt_def.is_union()
                 {
                     if let Some(assigned_ty) = self.assignment_info {
-                        if assigned_ty.needs_drop(self.tcx, self.param_env) {
+                        if assigned_ty.needs_drop(self.tcx, self.typing_env) {
                             // This would be unsafe, but should be outright impossible since we
                             // reject such unions.
                             assert!(
@@ -606,7 +647,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 if visitor.found {
                     match borrow_kind {
                         BorrowKind::Fake(_) | BorrowKind::Shared
-                            if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
+                            if !self.thir[arg].ty.is_freeze(self.tcx, self.typing_env) =>
                         {
                             self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
                         }
@@ -1024,7 +1065,8 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
         body_target_features,
         assignment_info: None,
         in_union_destructure: false,
-        param_env: tcx.param_env(def),
+        // FIXME(#132279): we're clearly in a body here.
+        typing_env: ty::TypingEnv::non_body_analysis(tcx, def),
         inside_adt: false,
         warnings: &mut warnings,
         suggest_unsafe_block: true,
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 00f65e0c7d0..676f7c98b8f 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -528,7 +528,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
         }
 
         if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
-            if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
+            if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.typing_env()) {
                 diag.note(fluent::mir_build_reference_note);
             }
         }
@@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     pub(crate) uncovered: Uncovered,
     #[subdiagnostic]
     pub(crate) inform: Option<Inform>,
+    #[label(mir_build_confused)]
+    pub(crate) interpreted_as_const: Option<Span>,
     #[subdiagnostic]
-    pub(crate) interpreted_as_const: Option<InterpretedAsConst>,
+    pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>,
     #[subdiagnostic]
     pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>,
     #[note(mir_build_privately_uninhabited)]
@@ -911,9 +913,9 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
 #[suggestion(
     mir_build_interpreted_as_const,
     code = "{variable}_var",
-    applicability = "maybe-incorrect"
+    applicability = "maybe-incorrect",
+    style = "verbose"
 )]
-#[label(mir_build_confused)]
 pub(crate) struct InterpretedAsConst {
     #[primary_span]
     pub(crate) span: Span,
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index cb9a4e2604e..5cf33868ade 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -132,15 +132,15 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> {
             return false;
         }
         let caller = body.source.def_id();
-        let param_env = tcx.param_env(caller);
+        let typing_env = body.typing_env(tcx);
 
         let func_ty = func.ty(body, tcx);
         if let ty::FnDef(callee, args) = *func_ty.kind() {
-            let Ok(normalized_args) = tcx.try_normalize_erasing_regions(param_env, args) else {
+            let Ok(normalized_args) = tcx.try_normalize_erasing_regions(typing_env, args) else {
                 return false;
             };
             let (callee, call_args) = if let Ok(Some(instance)) =
-                Instance::try_resolve(tcx, param_env, callee, normalized_args)
+                Instance::try_resolve(tcx, typing_env, callee, normalized_args)
             {
                 (instance.def_id(), instance.args)
             } else {
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index b8877a64e47..3fa0e4def82 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -2,7 +2,7 @@ use rustc_ast as ast;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
-use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
+use rustc_middle::ty::{self, ScalarInt, TyCtxt};
 use tracing::trace;
 
 use crate::build::parse_float_into_scalar;
@@ -14,8 +14,7 @@ pub(crate) fn lit_to_const<'tcx>(
     let LitToConstInput { lit, ty, neg } = lit_input;
 
     let trunc = |n| {
-        let param_ty = ParamEnv::reveal_all().and(ty);
-        let width = match tcx.layout_of(param_ty) {
+        let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
             Ok(layout) => layout.size,
             Err(_) => {
                 tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit))
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 64457031997..47b7f332951 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -23,7 +23,6 @@ use tracing::{debug, info, instrument, trace};
 
 use crate::errors;
 use crate::thir::cx::Cx;
-use crate::thir::cx::region::Scope;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
 impl<'tcx> Cx<'tcx> {
@@ -240,7 +239,7 @@ impl<'tcx> Cx<'tcx> {
     fn mirror_expr_cast(
         &mut self,
         source: &'tcx hir::Expr<'tcx>,
-        temp_lifetime: Option<Scope>,
+        temp_lifetime: TempLifetime,
         span: Span,
     ) -> ExprKind<'tcx> {
         let tcx = self.tcx;
@@ -284,10 +283,9 @@ impl<'tcx> Cx<'tcx> {
             let ty = adt_def.repr().discr_type();
             let discr_ty = ty.to_ty(tcx);
 
-            let param_env_ty = self.param_env.and(discr_ty);
             let size = tcx
-                .layout_of(param_env_ty)
-                .unwrap_or_else(|e| panic!("could not compute layout for {param_env_ty:?}: {e:?}"))
+                .layout_of(self.typing_env().as_query_input(discr_ty))
+                .unwrap_or_else(|e| panic!("could not compute layout for {discr_ty:?}: {e:?}"))
                 .size;
 
             let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size);
@@ -326,7 +324,7 @@ impl<'tcx> Cx<'tcx> {
     fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
         let tcx = self.tcx;
         let expr_ty = self.typeck_results().expr_ty(expr);
-        let temp_lifetime =
+        let (temp_lifetime, backwards_incompatible) =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
 
         let kind = match expr.kind {
@@ -362,7 +360,7 @@ impl<'tcx> Cx<'tcx> {
                     let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
                     let tupled_args = Expr {
                         ty: Ty::new_tup_from_iter(tcx, arg_tys),
-                        temp_lifetime,
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                         span: expr.span,
                         kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
                     };
@@ -392,7 +390,10 @@ impl<'tcx> Cx<'tcx> {
                                 && let [value] = args
                             {
                                 return Expr {
-                                    temp_lifetime,
+                                    temp_lifetime: TempLifetime {
+                                        temp_lifetime,
+                                        backwards_incompatible,
+                                    },
                                     ty: expr_ty,
                                     span: expr.span,
                                     kind: ExprKind::Box { value: self.mirror_expr(value) },
@@ -812,13 +813,13 @@ impl<'tcx> Cx<'tcx> {
             },
             hir::ExprKind::Loop(body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
-                let temp_lifetime = self
+                let (temp_lifetime, backwards_incompatible) = self
                     .rvalue_scopes
                     .temporary_scope(self.region_scope_tree, body.hir_id.local_id);
                 let block = self.mirror_block(body);
                 let body = self.thir.exprs.push(Expr {
                     ty: block_ty,
-                    temp_lifetime,
+                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                     span: self.thir[block].span,
                     kind: ExprKind::Block { block },
                 });
@@ -839,13 +840,17 @@ impl<'tcx> Cx<'tcx> {
                     expr, cast_ty.hir_id, user_ty,
                 );
 
-                let cast = self.mirror_expr_cast(source, temp_lifetime, expr.span);
+                let cast = self.mirror_expr_cast(
+                    source,
+                    TempLifetime { temp_lifetime, backwards_incompatible },
+                    expr.span,
+                );
 
                 if let Some(user_ty) = user_ty {
                     // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
                     //       inefficient, revisit this when performance becomes an issue.
                     let cast_expr = self.thir.exprs.push(Expr {
-                        temp_lifetime,
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                         ty: expr_ty,
                         span: expr.span,
                         kind: cast,
@@ -888,7 +893,12 @@ impl<'tcx> Cx<'tcx> {
             hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"),
         };
 
-        Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
+        Expr {
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+            ty: expr_ty,
+            span: expr.span,
+            kind,
+        }
     }
 
     fn user_args_applied_to_res(
@@ -932,7 +942,7 @@ impl<'tcx> Cx<'tcx> {
         span: Span,
         overloaded_callee: Option<Ty<'tcx>>,
     ) -> Expr<'tcx> {
-        let temp_lifetime =
+        let (temp_lifetime, backwards_incompatible) =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let (ty, user_ty) = match overloaded_callee {
             Some(fn_def) => (fn_def, None),
@@ -953,7 +963,12 @@ impl<'tcx> Cx<'tcx> {
                 )
             }
         };
-        Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } }
+        Expr {
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+            ty,
+            span,
+            kind: ExprKind::ZstLiteral { user_ty },
+        }
     }
 
     fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
@@ -1025,8 +1040,8 @@ impl<'tcx> Cx<'tcx> {
             // but distinguish between &STATIC and &THREAD_LOCAL as they have different semantics
             Res::Def(DefKind::Static { .. }, id) => {
                 // this is &raw for extern static or static mut, and & for other statics
-                let ty = self.tcx.static_ptr_ty(id);
-                let temp_lifetime = self
+                let ty = self.tcx.static_ptr_ty(id, self.typing_env());
+                let (temp_lifetime, backwards_incompatible) = self
                     .rvalue_scopes
                     .temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
                 let kind = if self.tcx.is_thread_local_static(id) {
@@ -1036,7 +1051,12 @@ impl<'tcx> Cx<'tcx> {
                     ExprKind::StaticRef { alloc_id, ty, def_id: id }
                 };
                 ExprKind::Deref {
-                    arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
+                    arg: self.thir.exprs.push(Expr {
+                        ty,
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                        span: expr.span,
+                        kind,
+                    }),
                 }
             }
 
@@ -1107,13 +1127,13 @@ impl<'tcx> Cx<'tcx> {
 
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
-        let temp_lifetime =
+        let (temp_lifetime, backwards_incompatible) =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let fun = self.method_callee(expr, span, overloaded_callee);
         let fun = self.thir.exprs.push(fun);
         let fun_ty = self.thir[fun].ty;
         let ref_expr = self.thir.exprs.push(Expr {
-            temp_lifetime,
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
             ty: ref_ty,
             span,
             kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span },
@@ -1128,7 +1148,7 @@ impl<'tcx> Cx<'tcx> {
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
     ) -> Expr<'tcx> {
-        let temp_lifetime = self
+        let (temp_lifetime, backwards_incompatible) = self
             .rvalue_scopes
             .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
@@ -1144,7 +1164,7 @@ impl<'tcx> Cx<'tcx> {
         };
 
         let mut captured_place_expr = Expr {
-            temp_lifetime,
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
             ty: var_ty,
             span: closure_expr.span,
             kind: self.convert_var(var_hir_id),
@@ -1169,8 +1189,12 @@ impl<'tcx> Cx<'tcx> {
                 }
             };
 
-            captured_place_expr =
-                Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
+            captured_place_expr = Expr {
+                temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                ty: proj.ty,
+                span: closure_expr.span,
+                kind,
+            };
         }
 
         captured_place_expr
@@ -1185,7 +1209,7 @@ impl<'tcx> Cx<'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
         let captured_place_expr =
             self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
-        let temp_lifetime = self
+        let (temp_lifetime, backwards_incompatible) = self
             .rvalue_scopes
             .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
 
@@ -1202,7 +1226,7 @@ impl<'tcx> Cx<'tcx> {
                     }
                 };
                 Expr {
-                    temp_lifetime,
+                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                     ty: upvar_ty,
                     span: closure_expr.span,
                     kind: ExprKind::Borrow {
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 377931e3be7..d47f7154c4b 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -12,6 +12,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::thir::*;
+use rustc_middle::ty::solve::Reveal;
 use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
 use tracing::instrument;
 
@@ -109,9 +110,20 @@ impl<'tcx> Cx<'tcx> {
         }
     }
 
+    fn typing_mode(&self) -> ty::TypingMode<'tcx> {
+        debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing);
+        // FIXME(#132279): In case we're in a body, we should use a typing
+        // mode which reveals the opaque types defined by that body.
+        ty::TypingMode::non_body_analysis()
+    }
+
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
+    }
+
     #[instrument(level = "debug", skip(self))]
     fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
-        pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
+        pat_from_hir(self.tcx, self.typing_env(), self.typeck_results(), p)
     }
 
     fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option<Param<'tcx>> {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index f222a869c03..27920008c80 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,6 +7,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_e
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
+use rustc_infer::traits::Reveal;
 use rustc_middle::bug;
 use rustc_middle::middle::limits::get_limit_size;
 use rustc_middle::thir::visit::Visitor;
@@ -191,6 +192,15 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
 }
 
 impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        // FIXME(#132279): We're in a body, should handle opaques.
+        debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing);
+        ty::TypingEnv {
+            typing_mode: ty::TypingMode::non_body_analysis(),
+            param_env: self.param_env,
+        }
+    }
+
     #[instrument(level = "trace", skip(self, f))]
     fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) {
         let old_let_source = self.let_source;
@@ -668,8 +678,25 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let mut let_suggestion = None;
         let mut misc_suggestion = None;
         let mut interpreted_as_const = None;
+        let mut interpreted_as_const_sugg = None;
 
-        if let PatKind::Constant { .. }
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
+        | PatKind::AscribeUserType {
+            subpattern:
+                box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
+            ..
+        } = pat.kind
+            && let DefKind::Const = self.tcx.def_kind(def_id)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
+            let span = self.tcx.def_span(def_id);
+            let variable = self.tcx.item_name(def_id).to_string();
+            // When we encounter a constant as the binding name, point at the `const` definition.
+            interpreted_as_const = Some(span);
+            interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
+        } else if let PatKind::Constant { .. }
         | PatKind::AscribeUserType {
             subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
             ..
@@ -682,9 +709,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral {
                     start_span: pat.span.shrink_to_lo(),
                 });
-            } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
-                interpreted_as_const =
-                    Some(InterpretedAsConst { span: pat.span, variable: snippet });
             }
         }
 
@@ -721,8 +745,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 .variant(*variant_index)
                 .inhabited_predicate(self.tcx, *adt)
                 .instantiate(self.tcx, args);
-            variant_inhabited.apply(self.tcx, cx.param_env, cx.module)
-                && !variant_inhabited.apply_ignore_module(self.tcx, cx.param_env)
+            variant_inhabited.apply(self.tcx, cx.typing_env(), cx.module)
+                && !variant_inhabited.apply_ignore_module(self.tcx, cx.typing_env())
         } else {
             false
         };
@@ -733,6 +757,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             uncovered: Uncovered::new(pat.span, &cx, witnesses),
             inform,
             interpreted_as_const,
+            interpreted_as_const_sugg,
             witness_1_is_privately_uninhabited,
             _p: (),
             pattern_ty,
@@ -760,7 +785,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
         return;
     };
 
-    let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
+    let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env());
 
     let sess = cx.tcx.sess;
 
@@ -1102,13 +1127,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
             if ty.is_ptr_sized_integral() {
                 if ty.inner() == cx.tcx.types.usize {
                     err.note(format!(
-                        "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have a fixed maximum value, so half-open ranges are \
+                         necessary to match exhaustively",
                     ));
                 } else if ty.inner() == cx.tcx.types.isize {
                     err.note(format!(
-                        "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have fixed minimum and maximum values, so half-open \
+                         ranges are necessary to match exhaustively",
                     ));
                 }
             } else if ty.inner() == cx.tcx.types.str_ {
@@ -1124,11 +1149,36 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     }
 
     if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
-        if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
+        if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.typing_env()) {
             err.note("references are always considered inhabited");
         }
     }
 
+    for &arm in arms {
+        let arm = &thir.arms[arm];
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
+            && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
+            let const_name = cx.tcx.item_name(def_id);
+            err.span_label(
+                arm.pattern.span,
+                format!(
+                    "this pattern doesn't introduce a new catch-all binding, but rather pattern \
+                     matches against the value of constant `{const_name}`",
+                ),
+            );
+            err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here"));
+            err.span_suggestion_verbose(
+                arm.pattern.span.shrink_to_hi(),
+                "if you meant to introduce a binding, use a different name",
+                "_var".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     // Whether we suggest the actual missing patterns or `_`.
     let suggest_the_witnesses = witnesses.len() < 4;
     let suggested_arm = if suggest_the_witnesses {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 82632350af5..a40134e44e7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -2,11 +2,11 @@ use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_apfloat::Float;
 use rustc_hir as hir;
 use rustc_index::Idx;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::Obligation;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
 use rustc_middle::{mir, span_bug};
 use rustc_span::Span;
 use rustc_trait_selection::traits::ObligationCause;
@@ -35,10 +35,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         id: hir::HirId,
         span: Span,
     ) -> Box<Pat<'tcx>> {
-        // FIXME(#132279): We likely want to be able to reveal the hidden types
-        // of opaques defined in this function here.
-        let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
-        let mut convert = ConstToPat::new(self, id, span, infcx);
+        let mut convert = ConstToPat::new(self, id, span);
 
         match c.kind() {
             ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
@@ -49,27 +46,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 }
 
 struct ConstToPat<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     span: Span,
-    param_env: ty::ParamEnv<'tcx>,
-
-    // inference context used for checking `T: Structural` bounds.
-    infcx: InferCtxt<'tcx>,
 
     treat_byte_string_as_slice: bool,
 }
 
 impl<'tcx> ConstToPat<'tcx> {
-    fn new(
-        pat_ctxt: &PatCtxt<'_, 'tcx>,
-        id: hir::HirId,
-        span: Span,
-        infcx: InferCtxt<'tcx>,
-    ) -> Self {
+    fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self {
         trace!(?pat_ctxt.typeck_results.hir_owner);
         ConstToPat {
+            tcx: pat_ctxt.tcx,
+            typing_env: pat_ctxt.typing_env,
             span,
-            infcx,
-            param_env: pat_ctxt.param_env,
             treat_byte_string_as_slice: pat_ctxt
                 .typeck_results
                 .treat_byte_string_as_slice
@@ -77,12 +67,8 @@ impl<'tcx> ConstToPat<'tcx> {
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
     fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_structural_eq_shallow(self.infcx.tcx)
+        ty.is_structural_eq_shallow(self.tcx)
     }
 
     fn unevaluated_to_pat(
@@ -100,22 +86,22 @@ impl<'tcx> ConstToPat<'tcx> {
         //
         // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
         // instead of having this logic here
-        let param_env =
-            self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx());
-        let uv = self.tcx().erase_regions(uv);
+        let typing_env =
+            self.tcx.erase_regions(self.typing_env).with_reveal_all_normalized(self.tcx);
+        let uv = self.tcx.erase_regions(uv);
 
         // try to resolve e.g. associated constants to their definition on an impl, and then
         // evaluate the const.
-        let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) {
+        let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) {
             Ok(Ok(c)) => c,
             Err(ErrorHandled::Reported(_, _)) => {
                 // Let's tell the use where this failing const occurs.
-                let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
+                let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
                 return pat_from_kind(PatKind::Error(e));
             }
             Err(ErrorHandled::TooGeneric(_)) => {
                 let e = self
-                    .tcx()
+                    .tcx
                     .dcx()
                     .emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
                 return pat_from_kind(PatKind::Error(e));
@@ -125,13 +111,13 @@ impl<'tcx> ConstToPat<'tcx> {
                 let e = match bad_ty.kind() {
                     ty::Adt(def, ..) => {
                         assert!(def.is_union());
-                        self.tcx().dcx().emit_err(UnionPattern { span: self.span })
+                        self.tcx.dcx().emit_err(UnionPattern { span: self.span })
                     }
                     ty::FnPtr(..) | ty::RawPtr(..) => {
-                        self.tcx().dcx().emit_err(PointerPattern { span: self.span })
+                        self.tcx.dcx().emit_err(PointerPattern { span: self.span })
                     }
                     _ => self
-                        .tcx()
+                        .tcx
                         .dcx()
                         .emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
                 };
@@ -146,7 +132,7 @@ impl<'tcx> ConstToPat<'tcx> {
             // Always check for `PartialEq` if we had no other errors yet.
             if !self.type_has_partial_eq_impl(ty) {
                 let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
-                let e = self.tcx().dcx().emit_err(err);
+                let e = self.tcx.dcx().emit_err(err);
                 return pat_from_kind(PatKind::Error(e));
             }
         }
@@ -156,18 +142,19 @@ impl<'tcx> ConstToPat<'tcx> {
 
     #[instrument(level = "trace", skip(self), ret)]
     fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
-        let tcx = self.tcx();
+        let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
         // double-check there even *is* a semantic `PartialEq` to dispatch to.
         //
         // (If there isn't, then we can safely issue a hard
         // error, because that's never worked, due to compiler
         // using `PartialEq::eq` in this scenario in the past.)
-        let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
+        let partial_eq_trait_id =
+            self.tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
         let partial_eq_obligation = Obligation::new(
-            tcx,
+            self.tcx,
             ObligationCause::dummy(),
-            self.param_env,
-            ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
+            param_env,
+            ty::TraitRef::new(self.tcx, partial_eq_trait_id, [ty, ty]),
         );
 
         // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
@@ -176,7 +163,7 @@ impl<'tcx> ConstToPat<'tcx> {
         // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
         // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
         // can ensure that the type really implements `PartialEq`.
-        self.infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
+        infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
     }
 
     fn field_pats(
@@ -187,7 +174,7 @@ impl<'tcx> ConstToPat<'tcx> {
             .map(|(idx, (val, ty))| {
                 let field = FieldIdx::new(idx);
                 // Patterns can only use monomorphic types.
-                let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
+                let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
                 FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
             })
             .collect()
@@ -197,14 +184,12 @@ impl<'tcx> ConstToPat<'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
         let span = self.span;
-        let tcx = self.tcx();
-        let param_env = self.param_env;
-
+        let tcx = self.tcx;
         let kind = match ty.kind() {
             ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
                 // Extremely important check for all ADTs! Make sure they opted-in to be used in
                 // patterns.
-                debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
+                debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
                 let err = TypeNotStructural { span, non_sm_ty: ty };
                 let e = tcx.dcx().emit_err(err);
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
@@ -222,7 +207,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             adt_def.variants()[variant_index]
                                 .fields
                                 .iter()
-                                .map(|field| field.ty(self.tcx(), args)),
+                                .map(|field| field.ty(self.tcx, args)),
                         ),
                     ),
                 }
@@ -230,14 +215,9 @@ impl<'tcx> ConstToPat<'tcx> {
             ty::Adt(def, args) => {
                 assert!(!def.is_union()); // Valtree construction would never succeed for unions.
                 PatKind::Leaf {
-                    subpatterns: self.field_pats(
-                        cv.unwrap_branch().iter().copied().zip(
-                            def.non_enum_variant()
-                                .fields
-                                .iter()
-                                .map(|field| field.ty(self.tcx(), args)),
-                        ),
-                    ),
+                    subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
+                        def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx, args)),
+                    )),
                 }
             }
             ty::Tuple(fields) => PatKind::Leaf {
@@ -271,7 +251,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 // convert the dereferenced constant to a pattern that is the sub-pattern of the
                 // deref pattern.
                 _ => {
-                    if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
+                    if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() {
                         let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
                         let e = tcx.dcx().emit_err(err);
                         // We errored. Signal that in the pattern, so that follow up errors can be silenced.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index ec852add94d..08c6b4abd3b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -30,7 +30,7 @@ use crate::thir::util::UserAnnotatedTyHelpers;
 
 struct PatCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
 
     /// Used by the Rust 2024 migration lint.
@@ -39,13 +39,13 @@ struct PatCtxt<'a, 'tcx> {
 
 pub(super) fn pat_from_hir<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
     pat: &'tcx hir::Pat<'tcx>,
 ) -> Box<Pat<'tcx>> {
     let mut pcx = PatCtxt {
         tcx,
-        param_env,
+        typing_env,
         typeck_results,
         rust_2024_migration_suggestion: typeck_results
             .rust_2024_migration_desugared_pats()
@@ -149,21 +149,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             None => Ok((None, None, None)),
             Some(expr) => {
                 let (kind, ascr, inline_const) = match self.lower_lit(expr) {
-                    PatKind::InlineConstant { subpattern, def } => {
-                        (subpattern.kind, None, Some(def))
+                    PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
+                        (subpattern.kind, None, def_id.as_local())
+                    }
+                    PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
+                        (subpattern.kind, None, None)
                     }
                     PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
                         (kind, Some(ascription), None)
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value } = kind {
-                    value
-                } else {
-                    let msg = format!(
-                        "found bad range pattern endpoint `{expr:?}` outside of error recovery"
-                    );
-                    return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                let value = match kind {
+                    PatKind::Constant { value } => value,
+                    PatKind::ExpandedConstant { subpattern, .. }
+                        if let PatKind::Constant { value } = subpattern.kind =>
+                    {
+                        value
+                    }
+                    _ => {
+                        let msg = format!(
+                            "found bad range pattern endpoint `{expr:?}` outside of error recovery"
+                        );
+                        return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                    }
                 };
                 Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
             }
@@ -242,7 +251,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity);
         let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity);
 
-        let cmp = lo.compare_with(hi, ty, self.tcx, self.param_env);
+        let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
         let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
         match (end, cmp) {
             // `x..y` where `x < y`.
@@ -288,7 +297,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             };
         }
         for def in [lo_inline, hi_inline].into_iter().flatten() {
-            kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
+            kind = PatKind::ExpandedConstant {
+                def_id: def.to_def_id(),
+                is_inline: true,
+                subpattern: Box::new(Pat { span, ty, kind }),
+            };
         }
         Ok(kind)
     }
@@ -562,7 +575,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
-        let pattern = self.const_to_pat(c, ty, id, span);
+        let subpattern = self.const_to_pat(c, ty, id, span);
+        let pattern = Box::new(Pat {
+            span,
+            ty,
+            kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
+        });
 
         if !is_associated_const {
             return pattern;
@@ -637,7 +655,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
         let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
-        PatKind::InlineConstant { subpattern, def: def_id }
+        PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
     }
 
     /// Converts literals, paths and negation of literals to patterns.
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index dae13df4054..6be0ed5fb31 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -707,9 +707,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::InlineConstant { def, subpattern } => {
-                print_indented!(self, "InlineConstant {", depth_lvl + 1);
-                print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
+            PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
+                print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
+                print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
+                print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
                 print_indented!(self, "subpattern:", depth_lvl + 2);
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 9a1f000d39d..494b7d54d8a 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -6,7 +6,6 @@ use rustc_index::Idx;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
-use rustc_middle::traits::Reveal;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
@@ -111,7 +110,7 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
     fn patch(&mut self) -> &mut MirPatch<'tcx>;
     fn body(&self) -> &'a Body<'tcx>;
     fn tcx(&self) -> TyCtxt<'tcx>;
-    fn param_env(&self) -> ty::ParamEnv<'tcx>;
+    fn typing_env(&self) -> ty::TypingEnv<'tcx>;
 
     // Drop logic
 
@@ -273,9 +272,9 @@ where
                 let subpath = self.elaborator.field_subpath(variant_path, field);
                 let tcx = self.tcx();
 
-                assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
+                assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
                 let field_ty =
-                    tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, args));
+                    tcx.normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args));
 
                 (tcx.mk_place_field(base_place, field, field_ty), subpath)
             })
@@ -372,7 +371,7 @@ where
 
         let mut fields = fields;
         fields.retain(|&(place, _)| {
-            self.place_ty(place).needs_drop(self.tcx(), self.elaborator.param_env())
+            self.place_ty(place).needs_drop(self.tcx(), self.elaborator.typing_env())
         });
 
         debug!("drop_ladder - fields needing drop: {:?}", fields);
@@ -544,11 +543,11 @@ where
             } else {
                 have_otherwise = true;
 
-                let param_env = self.elaborator.param_env();
+                let typing_env = self.elaborator.typing_env();
                 let have_field_with_drop_glue = variant
                     .fields
                     .iter()
-                    .any(|field| field.ty(tcx, args).needs_drop(tcx, param_env));
+                    .any(|field| field.ty(tcx, args).needs_drop(tcx, typing_env));
                 if have_field_with_drop_glue {
                     have_otherwise_with_drop_glue = true;
                 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 3e01f0512c4..9a5cf9d4e84 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -4,8 +4,8 @@ use rustc_middle::mir::{
     self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
 };
 
-use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{Analysis, Effect, EffectIndex, SwitchIntTarget};
+use super::visitor::ResultsVisitor;
+use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
 
 pub trait Direction {
     const IS_FORWARD: bool;
@@ -33,14 +33,14 @@ pub trait Direction {
     where
         A: Analysis<'tcx>;
 
-    fn visit_results_in_block<'mir, 'tcx, D, R>(
-        state: &mut D,
+    fn visit_results_in_block<'mir, 'tcx, A>(
+        state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
+        results: &mut Results<'tcx, A>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) where
-        R: ResultsVisitable<'tcx, Domain = D>;
+        A: Analysis<'tcx>;
 
     fn join_state_into_successors_of<'tcx, A>(
         analysis: &mut A,
@@ -53,7 +53,7 @@ pub trait Direction {
         A: Analysis<'tcx>;
 }
 
-/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement).
+/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
 pub struct Backward;
 
 impl Direction for Backward {
@@ -157,32 +157,32 @@ impl Direction for Backward {
         analysis.apply_statement_effect(state, statement, location);
     }
 
-    fn visit_results_in_block<'mir, 'tcx, D, R>(
-        state: &mut D,
+    fn visit_results_in_block<'mir, 'tcx, A>(
+        state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
+        results: &mut Results<'tcx, A>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) where
-        R: ResultsVisitable<'tcx, Domain = D>,
+        A: Analysis<'tcx>,
     {
-        results.reset_to_block_entry(state, block);
+        state.clone_from(results.entry_set_for_block(block));
 
         vis.visit_block_end(state);
 
         // Terminator
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.reconstruct_before_terminator_effect(state, term, loc);
+        results.analysis.apply_before_terminator_effect(state, term, loc);
         vis.visit_terminator_before_primary_effect(results, state, term, loc);
-        results.reconstruct_terminator_effect(state, term, loc);
+        results.analysis.apply_terminator_effect(state, term, loc);
         vis.visit_terminator_after_primary_effect(results, state, term, loc);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
             let loc = Location { block, statement_index };
-            results.reconstruct_before_statement_effect(state, stmt, loc);
+            results.analysis.apply_before_statement_effect(state, stmt, loc);
             vis.visit_statement_before_primary_effect(results, state, stmt, loc);
-            results.reconstruct_statement_effect(state, stmt, loc);
+            results.analysis.apply_statement_effect(state, stmt, loc);
             vis.visit_statement_after_primary_effect(results, state, stmt, loc);
         }
 
@@ -389,32 +389,32 @@ impl Direction for Forward {
         }
     }
 
-    fn visit_results_in_block<'mir, 'tcx, F, R>(
-        state: &mut F,
+    fn visit_results_in_block<'mir, 'tcx, A>(
+        state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>,
+        results: &mut Results<'tcx, A>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) where
-        R: ResultsVisitable<'tcx, Domain = F>,
+        A: Analysis<'tcx>,
     {
-        results.reset_to_block_entry(state, block);
+        state.clone_from(results.entry_set_for_block(block));
 
         vis.visit_block_start(state);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate() {
             let loc = Location { block, statement_index };
-            results.reconstruct_before_statement_effect(state, stmt, loc);
+            results.analysis.apply_before_statement_effect(state, stmt, loc);
             vis.visit_statement_before_primary_effect(results, state, stmt, loc);
-            results.reconstruct_statement_effect(state, stmt, loc);
+            results.analysis.apply_statement_effect(state, stmt, loc);
             vis.visit_statement_after_primary_effect(results, state, stmt, loc);
         }
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.reconstruct_before_terminator_effect(state, term, loc);
+        results.analysis.apply_before_terminator_effect(state, term, loc);
         vis.visit_terminator_before_primary_effect(results, state, term, loc);
-        results.reconstruct_terminator_effect(state, term, loc);
+        results.analysis.apply_terminator_effect(state, term, loc);
         vis.visit_terminator_after_primary_effect(results, state, term, loc);
 
         vis.visit_block_end(state);
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index bac75b972f9..98a4f58cb5d 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -544,20 +544,18 @@ impl<D> StateDiffCollector<D> {
     }
 }
 
-impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
+impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
 {
-    type Domain = A::Domain;
-
-    fn visit_block_start(&mut self, state: &Self::Domain) {
+    fn visit_block_start(&mut self, state: &A::Domain) {
         if A::Direction::IS_FORWARD {
             self.prev_state.clone_from(state);
         }
     }
 
-    fn visit_block_end(&mut self, state: &Self::Domain) {
+    fn visit_block_end(&mut self, state: &A::Domain) {
         if A::Direction::IS_BACKWARD {
             self.prev_state.clone_from(state);
         }
@@ -566,7 +564,7 @@ where
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -579,7 +577,7 @@ where
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -590,7 +588,7 @@ where
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
@@ -603,7 +601,7 @@ where
     fn visit_terminator_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 8f81da8bb04..244dfe26ad3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -55,8 +55,8 @@ mod visitor;
 pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
-pub use self::results::Results;
-pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
+pub use self::results::{EntrySets, Results};
+pub use self::visitor::{ResultsVisitor, visit_results};
 
 /// Analysis domains are all bitsets of various kinds. This trait holds
 /// operations needed by all of them.
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index 366fcbf33ba..ff6cafbfbae 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -18,7 +18,7 @@ use crate::errors::{
     DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
 };
 
-type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
+pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
 
 /// A dataflow analysis that has converged to fixpoint.
 #[derive(Clone)]
@@ -27,7 +27,7 @@ where
     A: Analysis<'tcx>,
 {
     pub analysis: A,
-    pub(super) entry_sets: EntrySets<'tcx, A>,
+    pub entry_sets: EntrySets<'tcx, A>,
 }
 
 impl<'tcx, A> Results<'tcx, A>
@@ -51,7 +51,7 @@ where
         &mut self,
         body: &'mir mir::Body<'tcx>,
         blocks: impl IntoIterator<Item = BasicBlock>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
         visit_results(body, blocks, self, vis)
     }
@@ -59,7 +59,7 @@ where
     pub fn visit_reachable_with<'mir>(
         &mut self,
         body: &'mir mir::Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
         let blocks = traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 3d6b008a684..5c7539eed4d 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results};
 
 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
 /// dataflow state at that location.
-pub fn visit_results<'mir, 'tcx, D, R>(
+pub fn visit_results<'mir, 'tcx, A>(
     body: &'mir mir::Body<'tcx>,
     blocks: impl IntoIterator<Item = BasicBlock>,
-    results: &mut R,
-    vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
+    results: &mut Results<'tcx, A>,
+    vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
 ) where
-    R: ResultsVisitable<'tcx, Domain = D>,
+    A: Analysis<'tcx>,
 {
-    let mut state = results.bottom_value(body);
+    let mut state = results.analysis.bottom_value(body);
 
     #[cfg(debug_assertions)]
     let reachable_blocks = mir::traversal::reachable_as_bitset(body);
@@ -22,23 +22,23 @@ pub fn visit_results<'mir, 'tcx, D, R>(
         assert!(reachable_blocks.contains(block));
 
         let block_data = &body[block];
-        R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
+        A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
     }
 }
 
-/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
-/// visited.
-pub trait ResultsVisitor<'mir, 'tcx, R> {
-    type Domain;
-
-    fn visit_block_start(&mut self, _state: &Self::Domain) {}
+/// A visitor over the results of an `Analysis`.
+pub trait ResultsVisitor<'mir, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    fn visit_block_start(&mut self, _state: &A::Domain) {}
 
     /// Called with the `before_statement_effect` of the given statement applied to `state` but not
     /// its `statement_effect`.
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -48,19 +48,19 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     /// statement applied to `state`.
     fn visit_statement_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
     ) {
     }
 
-    /// Called with the `before_terminator_effect` of the given terminator applied to `state` but not
-    /// its `terminator_effect`.
+    /// Called with the `before_terminator_effect` of the given terminator applied to `state` but
+    /// not its `terminator_effect`.
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) {
@@ -72,109 +72,12 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
     fn visit_terminator_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) {
     }
 
-    fn visit_block_end(&mut self, _state: &Self::Domain) {}
-}
-
-/// Things that can be visited by a `ResultsVisitor`.
-///
-/// This trait exists so that we can visit the results of one or more dataflow analyses
-/// simultaneously.
-pub trait ResultsVisitable<'tcx> {
-    type Direction: Direction;
-    type Domain;
-
-    /// Creates an empty `Domain` to hold the transient state for these dataflow results.
-    ///
-    /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry`
-    /// before it can be observed by a `ResultsVisitor`.
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
-
-    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock);
-
-    fn reconstruct_before_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    );
-
-    fn reconstruct_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    );
-
-    fn reconstruct_before_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    );
-
-    fn reconstruct_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    );
-}
-
-impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    type Domain = A::Domain;
-    type Direction = A::Direction;
-
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        self.analysis.bottom_value(body)
-    }
-
-    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
-        state.clone_from(self.entry_set_for_block(block));
-    }
-
-    fn reconstruct_before_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        stmt: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_before_statement_effect(state, stmt, loc);
-    }
-
-    fn reconstruct_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        stmt: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_statement_effect(state, stmt, loc);
-    }
-
-    fn reconstruct_before_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        term: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_before_terminator_effect(state, term, loc);
-    }
-
-    fn reconstruct_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        term: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_terminator_effect(state, term, loc);
-    }
+    fn visit_block_end(&mut self, _state: &A::Domain) {}
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index e06c1f2bb49..fd7254a0210 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -253,6 +253,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index c5fd2a631ff..576289e228a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -157,6 +157,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             | StatementKind::Nop
             | StatementKind::Retag(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::StorageLive(..) => {}
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b404e3bfb72..ab1453f1ed0 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{
     move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
 };
 pub use self::framework::{
-    Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
-    ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
+    Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
+    Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
     visit_results,
 };
 use self::move_paths::MoveData;
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index fd8e403ebc2..0880364bfca 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -385,6 +385,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 73abb669a11..10f1e009855 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
-use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results};
+use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
 
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
 pub struct DenseLocationMap {
@@ -95,14 +95,14 @@ rustc_index::newtype_index! {
 }
 
 /// Add points depending on the result of the given dataflow analysis.
-pub fn save_as_intervals<'tcx, N, R>(
+pub fn save_as_intervals<'tcx, N, A>(
     elements: &DenseLocationMap,
     body: &mir::Body<'tcx>,
-    mut results: R,
+    mut results: Results<'tcx, A>,
 ) -> SparseIntervalMatrix<N, PointIndex>
 where
     N: Idx,
-    R: ResultsVisitable<'tcx, Domain = BitSet<N>>,
+    A: Analysis<'tcx, Domain = BitSet<N>>,
 {
     let values = SparseIntervalMatrix::new(elements.num_points());
     let mut visitor = Visitor { elements, values };
@@ -120,16 +120,15 @@ struct Visitor<'a, N: Idx> {
     values: SparseIntervalMatrix<N, PointIndex>,
 }
 
-impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
+impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
 where
+    A: Analysis<'tcx, Domain = BitSet<N>>,
     N: Idx,
 {
-    type Domain = BitSet<N>;
-
     fn visit_statement_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -142,8 +141,8 @@ where
 
     fn visit_terminator_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) {
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index af2d514fc76..ed8678de1eb 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -462,7 +462,7 @@ impl<'tcx> Map<'tcx> {
         drop(assignments);
 
         // Create values for places whose type have scalar layout.
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         for place_info in self.places.iter_mut() {
             // The user requires a bound on the number of created values.
             if let Some(value_limit) = value_limit
@@ -471,13 +471,13 @@ impl<'tcx> Map<'tcx> {
                 break;
             }
 
-            if let Ok(ty) = tcx.try_normalize_erasing_regions(param_env, place_info.ty) {
+            if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, place_info.ty) {
                 place_info.ty = ty;
             }
 
             // Allocate a value slot if it doesn't have one, and the user requested one.
             assert!(place_info.value_index.is_none());
-            if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty))
+            if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(place_info.ty))
                 && layout.backend_repr.is_scalar()
             {
                 place_info.value_index = Some(self.value_count.into());
@@ -874,7 +874,7 @@ impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
 pub fn iter_fields<'tcx>(
     ty: Ty<'tcx>,
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     mut f: impl FnMut(Option<VariantIdx>, FieldIdx, Ty<'tcx>),
 ) {
     match ty.kind() {
@@ -892,20 +892,20 @@ pub fn iter_fields<'tcx>(
                 for (f_index, f_def) in v_def.fields.iter().enumerate() {
                     let field_ty = f_def.ty(tcx, args);
                     let field_ty = tcx
-                        .try_normalize_erasing_regions(param_env, field_ty)
+                        .try_normalize_erasing_regions(typing_env, field_ty)
                         .unwrap_or_else(|_| tcx.erase_regions(field_ty));
                     f(variant, f_index.into(), field_ty);
                 }
             }
         }
         ty::Closure(_, args) => {
-            iter_fields(args.as_closure().tupled_upvars_ty(), tcx, param_env, f);
+            iter_fields(args.as_closure().tupled_upvars_ty(), tcx, typing_env, f);
         }
         ty::Coroutine(_, args) => {
-            iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, param_env, f);
+            iter_fields(args.as_coroutine().tupled_upvars_ty(), tcx, typing_env, f);
         }
         ty::CoroutineClosure(_, args) => {
-            iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, param_env, f);
+            iter_fields(args.as_coroutine_closure().tupled_upvars_ty(), tcx, typing_env, f);
         }
         _ => (),
     }
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index 9bbfae17fd9..d00bfc66a6a 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -25,6 +25,31 @@ mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspen
     .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
 mir_transform_operation_will_panic = this operation will panic at runtime
 
+mir_transform_tail_expr_drop_order = relative drop order changing in Rust 2024
+    .temporaries = in Rust 2024, this temporary value will be dropped first
+    .observers = in Rust 2024, this local variable or temporary value will be dropped second
+    .note_dtors =
+        dropping the temporary value runs this custom `Drop` impl, which we could not prove to be side-effect free
+    .note_observer_dtors =
+        dropping the local runs this custom `Drop` impl, which we could not prove to be side-effect free
+    .drop_location =
+        now the temporary value is dropped here, before the local variables in the block or statement
+    .note_epilogue = most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+    .label_local_epilogue = {$is_dropped_first_edition_2024 ->
+        [true] up until Edition 2021 `{$name}` is dropped last but will be dropped earlier in Edition 2024
+        *[false] `{$name}` will be dropped later as of Edition 2024
+    }
+
+mir_transform_tail_expr_dtor = {$dtor_kind ->
+    [dyn] `{$name}` may invoke a custom destructor because it contains a trait object
+    *[concrete] `{$name}` invokes this custom destructor
+    }
+
+mir_transform_tail_expr_local = {$is_generated_name ->
+        [true] this value will be stored in a temporary; let us call it `{$name}`
+        *[false] `{$name}` calls a custom destructor
+    }
+
 mir_transform_unaligned_packed_ref = reference to packed field is unaligned
     .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
     .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index 559df222a50..12a2fe23b14 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
 use tracing::debug;
 
 use crate::util;
@@ -40,10 +40,10 @@ pub(super) struct AddMovesForPackedDrops;
 impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
-
-        let def_id = body.source.def_id();
         let mut patch = MirPatch::new(body);
-        let param_env = tcx.param_env(def_id);
+        // FIXME(#132279): This is used during the phase transition from analysis
+        // to runtime, so we have to manually specify the correct typing mode.
+        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
 
         for (bb, data) in body.basic_blocks.iter_enumerated() {
             let loc = Location { block: bb, statement_index: data.statements.len() };
@@ -51,7 +51,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
 
             match terminator.kind {
                 TerminatorKind::Drop { place, .. }
-                    if util::is_disaligned(tcx, body, param_env, place) =>
+                    if util::is_disaligned(tcx, body, typing_env, place) =>
                 {
                     add_move_for_packed_drop(
                         tcx,
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index a9600f77c0b..1b7c89fd251 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -3,7 +3,7 @@ use rustc_index::IndexVec;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::Session;
 use tracing::{debug, trace};
 
@@ -25,9 +25,9 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
             return;
         }
 
+        let typing_env = body.typing_env(tcx);
         let basic_blocks = body.basic_blocks.as_mut();
         let local_decls = &mut body.local_decls;
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
 
         // This pass inserts new blocks. Each insertion changes the Location for all
         // statements/blocks after. Iterating or visiting the MIR in order would require updating
@@ -41,7 +41,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
                 let source_info = statement.source_info;
 
                 let mut finder =
-                    PointerFinder { tcx, local_decls, param_env, pointers: Vec::new() };
+                    PointerFinder { tcx, local_decls, typing_env, pointers: Vec::new() };
                 finder.visit_statement(statement, location);
 
                 for (local, ty) in finder.pointers {
@@ -65,7 +65,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
 struct PointerFinder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a mut LocalDecls<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     pointers: Vec<(Place<'tcx>, Ty<'tcx>)>,
 }
 
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
         let pointee_ty =
             pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer");
         // Ideally we'd support this in the future, but for now we are limited to sized types.
-        if !pointee_ty.is_sized(self.tcx, self.param_env) {
+        if !pointee_ty.is_sized(self.tcx, self.typing_env) {
             debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty);
             return;
         }
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 1922d4fef25..e9b85ba6e9d 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -9,9 +9,9 @@ pub(super) struct CheckPackedRef;
 
 impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
-        let param_env = tcx.param_env(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         let source_info = SourceInfo::outermost(body.span);
-        let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
+        let mut checker = PackedRefChecker { body, tcx, typing_env, source_info };
         checker.visit_body(body);
     }
 }
@@ -19,7 +19,7 @@ impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
 struct PackedRefChecker<'a, 'tcx> {
     body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     source_info: SourceInfo,
 }
 
@@ -37,7 +37,8 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
     }
 
     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
+        if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place)
+        {
             let def_id = self.body.source.instance.def_id();
             if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
                 && self.tcx.is_builtin_derived(impl_def_id)
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 7d6ae9843b1..9b3443d3209 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -28,8 +28,8 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!(def_id = ?body.source.def_id());
 
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-        let ssa = SsaLocals::new(tcx, body, param_env);
+        let typing_env = body.typing_env(tcx);
+        let ssa = SsaLocals::new(tcx, body, typing_env);
 
         let fully_moved = fully_moved_locals(&ssa, body);
         debug!(?fully_moved);
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 063f220501f..8295a806d71 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -68,11 +68,11 @@ use rustc_middle::ty::{
     self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
 };
 use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
 use rustc_span::Span;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::sym;
@@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals {
 /// computation; see `CoroutineLayout` for more.
 fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
-    saved_locals: &CoroutineSavedLocals,
+    saved_locals: &'mir CoroutineSavedLocals,
     always_live_locals: BitSet<Local>,
-    mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
@@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> {
     eligible_storage_live: BitSet<Local>,
 }
 
-impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
+impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
     for StorageConflictVisitor<'a, 'tcx>
 {
-    type Domain = BitSet<Local>;
-
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        state: &BitSet<Local>,
         _statement: &'a Statement<'tcx>,
         loc: Location,
     ) {
@@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        state: &BitSet<Local>,
         _terminator: &'a Terminator<'tcx>,
         loc: Location,
     ) {
@@ -1071,11 +1069,9 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     // Note that `elaborate_drops` only drops the upvars of a coroutine, and
     // this is ok because `open_drop` can only be reached within that own
     // coroutine's resume function.
+    let typing_env = body.typing_env(tcx);
 
-    let def_id = body.source.def_id();
-    let param_env = tcx.param_env(def_id);
-
-    let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env };
+    let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, typing_env };
 
     for (block, block_data) in body.basic_blocks.iter_enumerated() {
         let (target, unwind, source_info) = match block_data.terminator() {
@@ -1206,9 +1202,9 @@ fn insert_panic_block<'tcx>(
     insert_term_block(body, kind)
 }
 
-fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
     // Returning from a function with an uninhabited return type is undefined behavior.
-    if body.return_ty().is_privately_uninhabited(tcx, param_env) {
+    if body.return_ty().is_privately_uninhabited(tcx, typing_env) {
         return false;
     }
 
@@ -1629,7 +1625,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
         // `storage_liveness` tells us which locals have live storage at suspension points
         let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
 
-        let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
+        let can_return = can_return(tcx, body, body.typing_env(tcx));
 
         // Run the transformation which converts Places from Local to coroutine struct
         // accesses for locals in `remap`.
@@ -1776,6 +1772,7 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs
index 59b403538a3..b23d8b9e737 100644
--- a/compiler/rustc_mir_transform/src/cost_checker.rs
+++ b/compiler/rustc_mir_transform/src/cost_checker.rs
@@ -1,7 +1,7 @@
 use rustc_middle::bug;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 
 const INSTR_COST: usize = 5;
 const CALL_PENALTY: usize = 25;
@@ -14,7 +14,7 @@ const CONST_SWITCH_BONUS: usize = 10;
 #[derive(Clone)]
 pub(super) struct CostChecker<'b, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     penalty: usize,
     bonus: usize,
     callee_body: &'b Body<'tcx>,
@@ -24,11 +24,11 @@ pub(super) struct CostChecker<'b, 'tcx> {
 impl<'b, 'tcx> CostChecker<'b, 'tcx> {
     pub(super) fn new(
         tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         instance: Option<ty::Instance<'tcx>>,
         callee_body: &'b Body<'tcx>,
     ) -> CostChecker<'b, 'tcx> {
-        CostChecker { tcx, param_env, callee_body, instance, penalty: 0, bonus: 0 }
+        CostChecker { tcx, typing_env, callee_body, instance, penalty: 0, bonus: 0 }
     }
 
     /// Add function-level costs not well-represented by the block-level costs.
@@ -119,7 +119,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
             TerminatorKind::Drop { place, unwind, .. } => {
                 // If the place doesn't actually need dropping, treat it like a regular goto.
                 let ty = self.instantiate_ty(place.ty(self.callee_body, self.tcx).ty);
-                if ty.needs_drop(self.tcx, self.param_env) {
+                if ty.needs_drop(self.tcx, self.typing_env) {
                     self.penalty += CALL_PENALTY;
                     if let UnwindAction::Cleanup(_) = unwind {
                         self.penalty += LANDINGPAD_PENALTY;
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 875db23ce09..824d657e1fc 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -97,6 +97,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
         | StatementKind::ConstEvalCounter
+        | StatementKind::BackwardIncompatibleDropHint { .. }
         | StatementKind::Nop => None,
 
         // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 7d073f1fa57..d017202f48b 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -16,7 +16,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::lattice::{FlatSet, HasBottom};
@@ -82,7 +82,7 @@ struct ConstAnalysis<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
@@ -144,13 +144,13 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
 
 impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self {
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         Self {
             map,
             tcx,
             local_decls: &body.local_decls,
-            ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
-            param_env,
+            ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
+            typing_env,
         }
     }
 
@@ -186,7 +186,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             | StatementKind::FakeRead(..)
             | StatementKind::PlaceMention(..)
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..) => (),
+            | StatementKind::BackwardIncompatibleDropHint { .. }
+            | StatementKind::AscribeUserType(..) => {}
         }
     }
 
@@ -389,7 +390,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                     && let Some(operand_ty) = operand_ty.builtin_deref(true)
                     && let ty::Array(_, len) = operand_ty.kind()
                     && let Some(len) = Const::Ty(self.tcx.types.usize, *len)
-                        .try_eval_scalar_int(self.tcx, self.param_env)
+                        .try_eval_scalar_int(self.tcx, self.typing_env)
                 {
                     state.insert_value_idx(target_len, FlatSet::Elem(len.into()), &self.map);
                 }
@@ -411,7 +412,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 let place_ty = place.ty(self.local_decls, self.tcx);
                 if let ty::Array(_, len) = place_ty.ty.kind() {
                     Const::Ty(self.tcx.types.usize, *len)
-                        .try_eval_scalar(self.tcx, self.param_env)
+                        .try_eval_scalar(self.tcx, self.typing_env)
                         .map_or(FlatSet::Top, FlatSet::Elem)
                 } else if let [ProjectionElem::Deref] = place.projection[..] {
                     state.get_len(place.local.into(), &self.map)
@@ -420,7 +421,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
             }
             Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
-                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
                     return ValueOrPlace::Value(FlatSet::Top);
                 };
                 match self.eval_operand(operand, state) {
@@ -434,7 +435,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
             }
             Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => {
-                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
                     return ValueOrPlace::Value(FlatSet::Top);
                 };
                 match self.eval_operand(operand, state) {
@@ -470,7 +471,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 FlatSet::Top => FlatSet::Top,
             },
             Rvalue::NullaryOp(null_op, ty) => {
-                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
                     return ValueOrPlace::Value(FlatSet::Top);
                 };
                 let val = match null_op {
@@ -479,7 +480,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                     NullOp::OffsetOf(fields) => self
                         .ecx
                         .tcx
-                        .offset_of_subfield(self.ecx.param_env(), layout, fields.iter())
+                        .offset_of_subfield(self.typing_env, layout, fields.iter())
                         .bytes(),
                     _ => return ValueOrPlace::Value(FlatSet::Top),
                 };
@@ -514,7 +515,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     ) -> FlatSet<Scalar> {
         constant
             .const_
-            .try_eval_scalar(self.tcx, self.param_env)
+            .try_eval_scalar(self.tcx, self.typing_env)
             .map_or(FlatSet::Top, FlatSet::Elem)
     }
 
@@ -554,7 +555,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 } else if rhs.projection.first() == Some(&PlaceElem::Deref)
                     && let FlatSet::Elem(pointer) = state.get(rhs.local.into(), &self.map)
                     && let rhs_ty = self.local_decls[rhs.local].ty
-                    && let Ok(rhs_layout) = self.tcx.layout_of(self.param_env.and(rhs_ty))
+                    && let Ok(rhs_layout) =
+                        self.tcx.layout_of(self.typing_env.as_query_input(rhs_ty))
                 {
                     let op = ImmTy::from_scalar(pointer, rhs_layout).into();
                     self.assign_constant(state, place, op, rhs.projection);
@@ -614,8 +616,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 TrackElem::DerefLen => {
                     let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into();
                     let len_usize = op.len(&self.ecx).discard_err()?;
-                    let layout =
-                        self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap();
+                    let layout = self
+                        .tcx
+                        .layout_of(self.typing_env.as_query_input(self.tcx.types.usize))
+                        .unwrap();
                     Some(ImmTy::from_uint(len_usize, layout).into())
                 }
             },
@@ -702,9 +706,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             FlatSet::Top => FlatSet::Top,
             FlatSet::Elem(scalar) => {
                 let ty = op.ty(self.local_decls, self.tcx);
-                self.tcx.layout_of(self.param_env.and(ty)).map_or(FlatSet::Top, |layout| {
-                    FlatSet::Elem(ImmTy::from_scalar(scalar, layout))
-                })
+                self.tcx
+                    .layout_of(self.typing_env.as_query_input(ty))
+                    .map_or(FlatSet::Top, |layout| {
+                        FlatSet::Elem(ImmTy::from_scalar(scalar, layout))
+                    })
             }
             FlatSet::Bottom => FlatSet::Bottom,
         }
@@ -714,7 +720,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         if !enum_ty.is_enum() {
             return None;
         }
-        let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?;
+        let enum_ty_layout = self.tcx.layout_of(self.typing_env.as_query_input(enum_ty)).ok()?;
         let discr_value =
             self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?;
         Some(discr_value.to_scalar())
@@ -941,16 +947,12 @@ fn try_write_constant<'tcx>(
     interp_ok(())
 }
 
-impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
-    for Collector<'_, 'tcx>
-{
-    type Domain = State<FlatSet<Scalar>>;
-
+impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
     #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -972,7 +974,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -997,7 +999,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 2898f82e25c..0c75cdadc92 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -99,7 +99,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 | StatementKind::Intrinsic(_)
                 | StatementKind::ConstEvalCounter
                 | StatementKind::PlaceMention(_)
-                | StatementKind::Nop => (),
+                | StatementKind::BackwardIncompatibleDropHint { .. }
+                | StatementKind::Nop => {}
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
                     bug!("{:?} not found in this MIR phase!", statement.kind)
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
index 753bae8e156..67b215c7c9d 100644
--- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -198,7 +198,7 @@ pub(super) fn deduced_param_attrs<'tcx>(
     // see [1].
     //
     // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
-    let param_env = tcx.param_env_reveal_all_normalized(def_id);
+    let typing_env = body.typing_env(tcx);
     let mut deduced_param_attrs = tcx.arena.alloc_from_iter(
         body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map(
             |(arg_index, local_decl)| DeducedParamAttrs {
@@ -207,8 +207,8 @@ pub(super) fn deduced_param_attrs<'tcx>(
                     // their generic parameters, otherwise we'll see exponential
                     // blow-up in compile times: #113372
                     && tcx
-                        .normalize_erasing_regions(param_env, local_decl.ty)
-                        .is_freeze(tcx, param_env),
+                        .normalize_erasing_regions(typing_env, local_decl.ty)
+                        .is_freeze(tcx, typing_env),
             },
         ),
     );
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index beeab0d4a66..9c74b2f0839 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -581,7 +581,7 @@ impl WriteInfo {
                     | Rvalue::RawPtr(_, _)
                     | Rvalue::Len(_)
                     | Rvalue::Discriminant(_)
-                    | Rvalue::CopyForDeref(_) => (),
+                    | Rvalue::CopyForDeref(_) => {}
                 }
             }
             // Retags are technically also reads, but reporting them as a write suffices
@@ -596,7 +596,8 @@ impl WriteInfo {
             | StatementKind::Coverage(_)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
-            | StatementKind::PlaceMention(_) => (),
+            | StatementKind::BackwardIncompatibleDropHint { .. }
+            | StatementKind::PlaceMention(_) => {}
             StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
                 bug!("{:?} not found in this MIR phase", statement)
             }
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 74572100db3..b0f041d8722 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -3,6 +3,7 @@ use std::fmt;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
+use rustc_infer::traits::Reveal;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
@@ -53,14 +54,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
     #[instrument(level = "trace", skip(self, tcx, body))]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
-
-        let def_id = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
+        // FIXME(#132279): This is used during the phase transition from analysis
+        // to runtime, so we have to manually specify the correct typing mode.
+        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
         // For types that do not need dropping, the behaviour is trivial. So we only need to track
         // init/uninit for types that do need dropping.
-        let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env));
+        let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, typing_env));
         let elaborate_patch = {
-            let env = MoveDataParamEnv { move_data, param_env };
+            let env = MoveDataParamEnv { move_data, param_env: typing_env.param_env };
 
             let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
                 .skipping_unreachable_unwind()
@@ -147,8 +148,8 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
         self.tcx
     }
 
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env()
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env()
     }
 
     #[instrument(level = "debug", skip(self), ret)]
@@ -250,6 +251,11 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
         self.env.param_env
     }
 
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        debug_assert_eq!(self.param_env().reveal(), Reveal::All);
+        ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env() }
+    }
+
     fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
         let patch = &mut self.patch;
         debug!("create_drop_flag({:?})", self.body.span);
@@ -335,7 +341,7 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
             if !place
                 .ty(&self.body.local_decls, self.tcx)
                 .ty
-                .needs_drop(self.tcx, self.env.param_env)
+                .needs_drop(self.tcx, self.typing_env())
             {
                 self.patch.patch_terminator(bb, TerminatorKind::Goto { target });
                 continue;
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 274eea9563f..976f4a8e919 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -100,7 +100,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::GlobalAlloc;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
@@ -120,12 +120,12 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!(def_id = ?body.source.def_id());
 
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-        let ssa = SsaLocals::new(tcx, body, param_env);
+        let typing_env = body.typing_env(tcx);
+        let ssa = SsaLocals::new(tcx, body, typing_env);
         // Clone dominators because we need them while mutating the body.
         let dominators = body.basic_blocks.dominators().clone();
 
-        let mut state = VnState::new(tcx, body, param_env, &ssa, dominators, &body.local_decls);
+        let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);
         ssa.for_each_assignment_mut(
             body.basic_blocks.as_mut_preserves_cfg(),
             |local, value, location| {
@@ -241,7 +241,6 @@ enum Value<'tcx> {
 struct VnState<'body, 'tcx> {
     tcx: TyCtxt<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
-    param_env: ty::ParamEnv<'tcx>,
     local_decls: &'body LocalDecls<'tcx>,
     /// Value stored in each local.
     locals: IndexVec<Local, Option<VnIndex>>,
@@ -266,7 +265,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ssa: &'body SsaLocals,
         dominators: Dominators<BasicBlock>,
         local_decls: &'body LocalDecls<'tcx>,
@@ -280,8 +279,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 + 4 * body.basic_blocks.len();
         VnState {
             tcx,
-            ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
-            param_env,
+            ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
             local_decls,
             locals: IndexVec::from_elem(None, local_decls),
             rev_locals: IndexVec::with_capacity(num_values),
@@ -295,6 +293,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         }
     }
 
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.ecx.typing_env()
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn insert(&mut self, value: Value<'tcx>) -> VnIndex {
         let (index, new) = self.values.insert_full(value);
@@ -343,7 +345,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         // Only register the value if its type is `Sized`, as we will emit copies of it.
         let is_sized = !self.feature_unsized_locals
-            || self.local_decls[local].ty.is_sized(self.tcx, self.param_env);
+            || self.local_decls[local].ty.is_sized(self.tcx, self.typing_env());
         if is_sized {
             self.rev_locals[value].push(local);
         }
@@ -531,7 +533,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     NullOp::OffsetOf(fields) => self
                         .ecx
                         .tcx
-                        .offset_of_subfield(self.ecx.param_env(), layout, fields.iter())
+                        .offset_of_subfield(self.typing_env(), layout, fields.iter())
                         .bytes(),
                     NullOp::UbChecks => return None,
                 };
@@ -638,7 +640,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 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.param_env)
+                    && pointee_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`.
@@ -1057,7 +1059,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 && 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.param_env)
+                && from_pointee_ty.is_sized(self.tcx, self.typing_env())
             {
                 fields[0] = *cast_value;
                 *data_pointer_ty = *cast_from;
@@ -1379,7 +1381,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
                 self.get(value)
             && let ty::RawPtr(to_pointee, _) = to.kind()
-            && to_pointee.is_sized(self.tcx, self.param_env)
+            && to_pointee.is_sized(self.tcx, self.typing_env())
         {
             from = *data_pointer_ty;
             value = fields[0];
@@ -1476,8 +1478,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         if left_meta_ty == right_meta_ty {
             true
         } else if let Ok(left) =
-            self.tcx.try_normalize_erasing_regions(self.param_env, left_meta_ty)
-            && let Ok(right) = self.tcx.try_normalize_erasing_regions(self.param_env, right_meta_ty)
+            self.tcx.try_normalize_erasing_regions(self.typing_env(), left_meta_ty)
+            && let Ok(right) =
+                self.tcx.try_normalize_erasing_regions(self.typing_env(), right_meta_ty)
         {
             left == right
         } else {
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index e95ab4ffe16..00f6c3845d4 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -13,9 +13,7 @@ use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{
-    self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags, TypeVisitableExt,
-};
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
 use rustc_session::config::{DebugInfo, OptLevel};
 use rustc_span::source_map::Spanned;
 use rustc_span::sym;
@@ -94,12 +92,12 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
         return false;
     }
 
-    let param_env = tcx.param_env_reveal_all_normalized(def_id);
+    let typing_env = body.typing_env(tcx);
     let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
 
     let mut this = Inliner {
         tcx,
-        param_env,
+        typing_env,
         codegen_fn_attrs,
         history: Vec::new(),
         changed: false,
@@ -115,7 +113,7 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
 
 struct Inliner<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
     /// Stack of inlined instances.
@@ -201,7 +199,8 @@ impl<'tcx> Inliner<'tcx> {
         let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
         let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
         for arg in args {
-            if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.param_env) {
+            if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.typing_env)
+            {
                 // We do not allow inlining functions with unsized params. Inlining these functions
                 // could create unsized locals, which are unsound and being phased out.
                 return Err("Call has unsized argument");
@@ -219,7 +218,7 @@ impl<'tcx> Inliner<'tcx> {
 
         let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions(
             self.tcx,
-            self.param_env,
+            self.typing_env,
             ty::EarlyBinder::bind(callee_body.clone()),
         ) else {
             return Err("failed to normalize callee body");
@@ -230,7 +229,7 @@ impl<'tcx> Inliner<'tcx> {
         if !validate_types(
             self.tcx,
             MirPhase::Runtime(RuntimePhase::Optimized),
-            self.param_env,
+            self.typing_env,
             &callee_body,
             &caller_body,
         )
@@ -243,13 +242,7 @@ impl<'tcx> Inliner<'tcx> {
         // Normally, this shouldn't be required, but trait normalization failure can create a
         // validation ICE.
         let output_type = callee_body.return_ty();
-        if !util::sub_types(
-            self.tcx,
-            caller_body.typing_mode(self.tcx),
-            self.param_env,
-            output_type,
-            destination_ty,
-        ) {
+        if !util::sub_types(self.tcx, self.typing_env, output_type, destination_ty) {
             trace!(?output_type, ?destination_ty);
             return Err("failed to normalize return type");
         }
@@ -279,13 +272,7 @@ impl<'tcx> Inliner<'tcx> {
                 self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
             {
                 let input_type = callee_body.local_decls[input].ty;
-                if !util::sub_types(
-                    self.tcx,
-                    caller_body.typing_mode(self.tcx),
-                    self.param_env,
-                    input_type,
-                    arg_ty,
-                ) {
+                if !util::sub_types(self.tcx, self.typing_env, input_type, arg_ty) {
                     trace!(?arg_ty, ?input_type);
                     return Err("failed to normalize tuple argument type");
                 }
@@ -294,13 +281,7 @@ impl<'tcx> Inliner<'tcx> {
             for (arg, input) in args.iter().zip(callee_body.args_iter()) {
                 let input_type = callee_body.local_decls[input].ty;
                 let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx);
-                if !util::sub_types(
-                    self.tcx,
-                    caller_body.typing_mode(self.tcx),
-                    self.param_env,
-                    input_type,
-                    arg_ty,
-                ) {
+                if !util::sub_types(self.tcx, self.typing_env, input_type, arg_ty) {
                     trace!(?arg_ty, ?input_type);
                     return Err("failed to normalize argument type");
                 }
@@ -402,9 +383,10 @@ impl<'tcx> Inliner<'tcx> {
             let func_ty = func.ty(caller_body, self.tcx);
             if let ty::FnDef(def_id, args) = *func_ty.kind() {
                 // To resolve an instance its args have to be fully normalized.
-                let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?;
-                let callee =
-                    Instance::try_resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?;
+                let args = self.tcx.try_normalize_erasing_regions(self.typing_env, args).ok()?;
+                let callee = Instance::try_resolve(self.tcx, self.typing_env, def_id, args)
+                    .ok()
+                    .flatten()?;
 
                 if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def {
                     return None;
@@ -528,7 +510,7 @@ impl<'tcx> Inliner<'tcx> {
         // FIXME: Give a bonus to functions with only a single caller
 
         let mut checker =
-            CostChecker::new(self.tcx, self.param_env, Some(callsite.callee), callee_body);
+            CostChecker::new(self.tcx, self.typing_env, Some(callsite.callee), callee_body);
 
         checker.add_function_level_costs();
 
@@ -552,7 +534,7 @@ impl<'tcx> Inliner<'tcx> {
                     self.tcx,
                     ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty),
                 );
-                if ty.needs_drop(tcx, self.param_env)
+                if ty.needs_drop(tcx, self.typing_env)
                     && let UnwindAction::Cleanup(unwind) = unwind
                 {
                     work_list.push(unwind);
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 9828e90de88..a40768300f5 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -15,7 +15,6 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
     (root, target): (ty::Instance<'tcx>, LocalDefId),
 ) -> bool {
     trace!(%root, target = %tcx.def_path_str(target));
-    let param_env = tcx.param_env_reveal_all_normalized(target);
     assert_ne!(
         root.def_id().expect_local(),
         target,
@@ -31,11 +30,11 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
     );
     #[instrument(
         level = "debug",
-        skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit)
+        skip(tcx, typing_env, target, stack, seen, recursion_limiter, caller, recursion_limit)
     )]
     fn process<'tcx>(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         caller: ty::Instance<'tcx>,
         target: LocalDefId,
         stack: &mut Vec<ty::Instance<'tcx>>,
@@ -47,13 +46,13 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
         for &(callee, args) in tcx.mir_inliner_callees(caller.def) {
             let Ok(args) = caller.try_instantiate_mir_and_normalize_erasing_regions(
                 tcx,
-                param_env,
+                typing_env,
                 ty::EarlyBinder::bind(args),
             ) else {
-                trace!(?caller, ?param_env, ?args, "cannot normalize, skipping");
+                trace!(?caller, ?typing_env, ?args, "cannot normalize, skipping");
                 continue;
             };
-            let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, param_env, callee, args) else {
+            let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, typing_env, callee, args) else {
                 trace!(?callee, "cannot resolve, skipping");
                 continue;
             };
@@ -115,7 +114,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
                     let found_recursion = ensure_sufficient_stack(|| {
                         process(
                             tcx,
-                            param_env,
+                            typing_env,
                             callee,
                             target,
                             stack,
@@ -146,7 +145,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
     let recursion_limit = tcx.recursion_limit() / 2;
     process(
         tcx,
-        param_env,
+        ty::TypingEnv::post_analysis(tcx, target),
         root,
         target,
         &mut Vec::new(),
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 9471c1b2a9a..3352d583f2c 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -6,7 +6,7 @@ use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::ValidityRequirement;
-use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, layout};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
@@ -34,7 +34,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
         let ctx = InstSimplifyContext {
             tcx,
             local_decls: &body.local_decls,
-            param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
+            typing_env: body.typing_env(tcx),
         };
         let preserve_ub_checks =
             attr::contains_name(tcx.hir().krate_attrs(), sym::rustc_preserve_ub_checks);
@@ -66,7 +66,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
 struct InstSimplifyContext<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> InstSimplifyContext<'_, 'tcx> {
@@ -348,7 +348,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
         }
 
         let known_is_valid =
-            intrinsic_assert_panics(self.tcx, self.param_env, args[0], intrinsic_name);
+            intrinsic_assert_panics(self.tcx, self.typing_env, args[0], intrinsic_name);
         match known_is_valid {
             // We don't know the layout or it's not validity assertion at all, don't touch it
             None => {}
@@ -366,13 +366,13 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
 
 fn intrinsic_assert_panics<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     arg: ty::GenericArg<'tcx>,
     intrinsic_name: Symbol,
 ) -> Option<bool> {
     let requirement = ValidityRequirement::from_intrinsic(intrinsic_name)?;
     let ty = arg.expect_ty();
-    Some(!tcx.check_validity_requirement((requirement, param_env.and(ty))).ok()?)
+    Some(!tcx.check_validity_requirement((requirement, typing_env.as_query_input(ty))).ok()?)
 }
 
 fn resolve_rust_intrinsic<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 3772589ac4e..beed007589b 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -77,13 +77,12 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
             return;
         }
 
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
-
+        let typing_env = body.typing_env(tcx);
         let arena = &DroplessArena::default();
         let mut finder = TOFinder {
             tcx,
-            param_env,
-            ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
+            typing_env,
+            ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
             body,
             arena,
             map: Map::new(tcx, body, Some(MAX_PLACES)),
@@ -119,7 +118,7 @@ struct ThreadingOpportunity {
 
 struct TOFinder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
     body: &'a Body<'tcx>,
     map: Map<'tcx>,
@@ -207,7 +206,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
         let Some(discr) = self.map.find(discr.as_ref()) else { return };
         debug!(?discr);
 
-        let cost = CostChecker::new(self.tcx, self.param_env, None, self.body);
+        let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body);
         let mut state = State::new_reachable();
 
         let conds = if let Some((value, then, else_)) = targets.as_static_if() {
@@ -353,6 +352,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
             | StatementKind::FakeRead(..)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => None,
         }
     }
@@ -528,7 +528,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
                     // Avoid handling them, though this could be extended in the future.
                     return;
                 }
-                let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.param_env) else {
+                let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env)
+                else {
                     return;
                 };
                 let conds = conditions.map(self.arena, |c| Condition {
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 0604665642a..53e282e9b46 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -18,7 +18,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ConstInt, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::Span;
 use tracing::{debug, instrument, trace};
 
@@ -65,7 +65,7 @@ impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint {
 struct ConstPropagator<'mir, 'tcx> {
     ecx: InterpCx<'tcx, DummyMachine>,
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     worklist: Vec<BasicBlock>,
     visited_blocks: BitSet<BasicBlock>,
     locals: IndexVec<Local, Value<'tcx>>,
@@ -169,25 +169,26 @@ impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> {
     }
 }
 
-impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
+impl<'tcx> ty::layout::HasTypingEnv<'tcx> for ConstPropagator<'_, 'tcx> {
     #[inline]
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
     }
 }
 
 impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
         let def_id = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
-
-        let can_const_prop = CanConstProp::check(tcx, param_env, body);
-        let ecx = InterpCx::new(tcx, tcx.def_span(def_id), param_env, DummyMachine);
+        // FIXME(#132279): This is used during the phase transition from analysis
+        // to runtime, so we have to manually specify the correct typing mode.
+        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
+        let can_const_prop = CanConstProp::check(tcx, typing_env, body);
+        let ecx = InterpCx::new(tcx, tcx.def_span(def_id), typing_env, DummyMachine);
 
         ConstPropagator {
             ecx,
             tcx,
-            param_env,
+            typing_env,
             worklist: vec![START_BLOCK],
             visited_blocks: BitSet::new_empty(body.basic_blocks.len()),
             locals: IndexVec::from_elem_n(Value::Uninit, body.local_decls.len()),
@@ -260,7 +261,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         // that the `RevealAll` pass has happened and that the body's consts
         // are normalized, so any call to resolve before that needs to be
         // manually normalized.
-        let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?;
+        let val = self.tcx.try_normalize_erasing_regions(self.typing_env, c.const_).ok()?;
 
         self.use_ecx(|this| this.ecx.eval_mir_constant(&val, c.span, None))?
             .as_mplace_or_imm()
@@ -450,7 +451,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         if rvalue.has_param() {
             return None;
         }
-        if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) {
+        if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.typing_env) {
             // the interpreter doesn't support unsized locals (only unsized arguments),
             // but rustc does (in a kinda broken way), so we have to skip them here
             return None;
@@ -622,7 +623,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     NullOp::AlignOf => op_layout.align.abi.bytes(),
                     NullOp::OffsetOf(fields) => self
                         .tcx
-                        .offset_of_subfield(self.param_env, op_layout, fields.iter())
+                        .offset_of_subfield(self.typing_env, op_layout, fields.iter())
                         .bytes(),
                     NullOp::UbChecks => return None,
                 };
@@ -873,7 +874,7 @@ impl CanConstProp {
     /// Returns true if `local` can be propagated
     fn check<'tcx>(
         tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         body: &Body<'tcx>,
     ) -> IndexVec<Local, ConstPropMode> {
         let mut cpv = CanConstProp {
@@ -888,7 +889,7 @@ impl CanConstProp {
                 // variant of a union
                 *val = ConstPropMode::NoPropagation;
             } else {
-                match tcx.layout_of(param_env.and(ty)) {
+                match tcx.layout_of(typing_env.as_query_input(ty)) {
                     Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
                     // Either the layout fails to compute, then we can't use this local anyway
                     // or the local is too large, then we don't want to.
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index fa659a56a27..8be5a63d008 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::*;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_session::Session;
 
 /// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
@@ -39,8 +39,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
         // platform, but it will still be valid.
 
         let mut alloc_cache = FxHashMap::default();
-        let body_did = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(body_did);
+        let typing_env = body.typing_env(tcx);
 
         let blocks = body.basic_blocks.as_mut();
         let local_decls = &mut body.local_decls;
@@ -58,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
                 let ty = lhs.ty(local_decls, tcx).ty;
 
                 let (adt_def, num_variants, alloc_id) =
-                    self.candidate(tcx, param_env, ty, &mut alloc_cache)?;
+                    self.candidate(tcx, typing_env, ty, &mut alloc_cache)?;
 
                 let source_info = st.source_info;
                 let span = source_info.span;
@@ -207,7 +206,7 @@ impl EnumSizeOpt {
     fn candidate<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ty: Ty<'tcx>,
         alloc_cache: &mut FxHashMap<Ty<'tcx>, AllocId>,
     ) -> Option<(AdtDef<'tcx>, usize, AllocId)> {
@@ -215,7 +214,7 @@ impl EnumSizeOpt {
             ty::Adt(adt_def, _args) if adt_def.is_enum() => adt_def,
             _ => return None,
         };
-        let layout = tcx.layout_of(param_env.and(ty)).ok()?;
+        let layout = tcx.layout_of(typing_env.as_query_input(ty)).ok()?;
         let variants = match &layout.variants {
             Variants::Single { .. } => return None,
             Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => return None,
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index d2d5facbbdc..bfb842e4485 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -50,6 +50,7 @@ mod deduce_param_attrs;
 mod errors;
 mod ffi_unwind_calls;
 mod lint;
+mod lint_tail_expr_drop_order;
 mod shim;
 mod ssa;
 
@@ -333,10 +334,14 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
 }
 
 fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
-    let const_kind = tcx.hir().body_const_context(def);
-
+    // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
+    // cannot yet be stolen), because `mir_promoted()`, which steals
+    // from `mir_built()`, forces this query to execute before
+    // performing the steal.
+    let body = &tcx.mir_built(def).borrow();
+    let ccx = check_consts::ConstCx::new(tcx, body);
     // No need to const-check a non-const `fn`.
-    match const_kind {
+    match ccx.const_kind {
         Some(ConstContext::Const { .. } | ConstContext::Static(_) | ConstContext::ConstFn) => {}
         None => span_bug!(
             tcx.def_span(def),
@@ -344,20 +349,12 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
         ),
     }
 
-    // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
-    // cannot yet be stolen), because `mir_promoted()`, which steals
-    // from `mir_built()`, forces this query to execute before
-    // performing the steal.
-    let body = &tcx.mir_built(def).borrow();
-
     if body.return_ty().references_error() {
         // It's possible to reach here without an error being emitted (#121103).
         tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors");
         return Default::default();
     }
 
-    let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def) };
-
     let mut validator = check_consts::check::Checker::new(&ccx);
     validator.check_body();
 
@@ -494,6 +491,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
     }
 
     let (body, _) = tcx.mir_promoted(def);
+    lint_tail_expr_drop_order::run_lint(tcx, def, &body.borrow());
     let mut body = body.steal();
 
     if let Some(error_reported) = tainted_by_errors {
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
new file mode 100644
index 00000000000..b8502fcbafb
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -0,0 +1,701 @@
+use std::cell::RefCell;
+use std::collections::hash_map;
+use std::rc::Rc;
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
+use rustc_errors::Subdiagnostic;
+use rustc_hir::CRATE_HIR_ID;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_index::bit_set::ChunkedBitSet;
+use rustc_index::{IndexSlice, IndexVec};
+use rustc_macros::{LintDiagnostic, Subdiagnostic};
+use rustc_middle::bug;
+use rustc_middle::mir::{
+    self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind,
+    dump_mir,
+};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
+use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor};
+use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER;
+use rustc_session::lint::{self};
+use rustc_span::{DUMMY_SP, Span, Symbol};
+use rustc_type_ir::data_structures::IndexMap;
+use smallvec::{SmallVec, smallvec};
+use tracing::{debug, instrument};
+
+fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool {
+    left.local == right.local
+        && left.projection.iter().zip(right.projection).all(|(left, right)| left == right)
+}
+
+/// Cache entry of `drop` at a `BasicBlock`
+#[derive(Debug, Clone, Copy)]
+enum MovePathIndexAtBlock {
+    /// We know nothing yet
+    Unknown,
+    /// We know that the `drop` here has no effect
+    None,
+    /// We know that the `drop` here will invoke a destructor
+    Some(MovePathIndex),
+}
+
+struct DropsReachable<'a, 'mir, 'tcx> {
+    body: &'a Body<'tcx>,
+    place: &'a Place<'tcx>,
+    drop_span: &'a mut Option<Span>,
+    move_data: &'a MoveData<'tcx>,
+    maybe_init: &'a mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
+    block_drop_value_info: &'a mut IndexSlice<BasicBlock, MovePathIndexAtBlock>,
+    collected_drops: &'a mut ChunkedBitSet<MovePathIndex>,
+    visited: FxHashMap<BasicBlock, Rc<RefCell<ChunkedBitSet<MovePathIndex>>>>,
+}
+
+impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
+    fn visit(&mut self, block: BasicBlock) {
+        let move_set_size = self.move_data.move_paths.len();
+        let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size)));
+
+        let data = &self.body.basic_blocks[block];
+        let Some(terminator) = &data.terminator else { return };
+        // Given that we observe these dropped locals here at `block` so far,
+        // we will try to update the successor blocks.
+        // An occupied entry at `block` in `self.visited` signals that we have visited `block` before.
+        let dropped_local_here =
+            Rc::clone(self.visited.entry(block).or_insert_with(make_new_path_set));
+        // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive.
+        // Let's cache them in `self.block_drop_value_info`.
+        match self.block_drop_value_info[block] {
+            MovePathIndexAtBlock::Some(dropped) => {
+                dropped_local_here.borrow_mut().insert(dropped);
+            }
+            MovePathIndexAtBlock::Unknown => {
+                if let TerminatorKind::Drop { place, .. } = &terminator.kind
+                    && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) =
+                        self.move_data.rev_lookup.find(place.as_ref())
+                {
+                    // Since we are working with MIRs at a very early stage,
+                    // observing a `drop` terminator is not indicative enough that
+                    // the drop will definitely happen.
+                    // That is decided in the drop elaboration pass instead.
+                    // Therefore, we need to consult with the maybe-initialization information.
+                    self.maybe_init.seek_before_primary_effect(Location {
+                        block,
+                        statement_index: data.statements.len(),
+                    });
+
+                    // Check if the drop of `place` under inspection is really in effect.
+                    // This is true only when `place` may have been initialized along a control flow path from a BID to the drop program point today.
+                    // In other words, this is where the drop of `place` will happen in the future instead.
+                    if let MaybeReachable::Reachable(maybe_init) = self.maybe_init.get()
+                        && maybe_init.contains(idx)
+                    {
+                        // We also cache the drop information, so that we do not need to check on data-flow cursor again
+                        self.block_drop_value_info[block] = MovePathIndexAtBlock::Some(idx);
+                        dropped_local_here.borrow_mut().insert(idx);
+                    } else {
+                        self.block_drop_value_info[block] = MovePathIndexAtBlock::None;
+                    }
+                }
+            }
+            MovePathIndexAtBlock::None => {}
+        }
+
+        for succ in terminator.successors() {
+            let target = &self.body.basic_blocks[succ];
+            if target.is_cleanup {
+                continue;
+            }
+
+            // As long as we are passing through a new block, or new dropped places to propagate,
+            // we will proceed with `succ`
+            let dropped_local_there = match self.visited.entry(succ) {
+                hash_map::Entry::Occupied(occupied_entry) => {
+                    if succ == block
+                        || !occupied_entry.get().borrow_mut().union(&*dropped_local_here.borrow())
+                    {
+                        // `succ` has been visited but no new drops observed so far,
+                        // so we can bail on `succ` until new drop information arrives
+                        continue;
+                    }
+                    Rc::clone(occupied_entry.get())
+                }
+                hash_map::Entry::Vacant(vacant_entry) => Rc::clone(
+                    vacant_entry.insert(Rc::new(RefCell::new(dropped_local_here.borrow().clone()))),
+                ),
+            };
+            if let Some(terminator) = &target.terminator
+                && let TerminatorKind::Drop {
+                    place: dropped_place,
+                    target: _,
+                    unwind: _,
+                    replace: _,
+                } = &terminator.kind
+                && place_has_common_prefix(dropped_place, self.place)
+            {
+                // We have now reached the current drop of the `place`.
+                // Let's check the observed dropped places in.
+                self.collected_drops.union(&*dropped_local_there.borrow());
+                if self.drop_span.is_none() {
+                    // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky.
+                    // There is a high chance that this span still points to a block rather than a statement semicolon.
+                    *self.drop_span = Some(terminator.source_info.span);
+                }
+                // Now we have discovered a simple control flow path from a future drop point
+                // to the current drop point.
+                // We will not continue from there.
+            } else {
+                self.visit(succ)
+            }
+        }
+    }
+}
+
+/// An additional filter to exclude well-known types from the ecosystem
+/// because their drops are trivial.
+/// This returns additional types to check if the drops are delegated to those.
+/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
+fn true_significant_drop_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
+    if let ty::Adt(def, args) = ty.kind() {
+        let mut did = def.did();
+        let mut name_rev = vec![];
+        loop {
+            let key = tcx.def_key(did);
+
+            match key.disambiguated_data.data {
+                rustc_hir::definitions::DefPathData::CrateRoot => {
+                    name_rev.push(tcx.crate_name(did.krate))
+                }
+                rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
+                _ => return None,
+            }
+            if let Some(parent) = key.parent {
+                did = DefId { krate: did.krate, index: parent };
+            } else {
+                break;
+            }
+        }
+        let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
+        debug!(?name_str);
+        match name_str[..] {
+            // These are the types from Rust core ecosystem
+            ["sym" | "proc_macro2", ..]
+            | ["core" | "std", "task", "LocalWaker" | "Waker"]
+            | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
+            // These are important types from Rust ecosystem
+            ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
+            ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
+                if let [ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            ["hashbrown", "raw", "RawDrain"] => {
+                if let [_, ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+/// Returns the list of types with a "potentially sigificant" that may be dropped
+/// by dropping a value of type `ty`.
+#[instrument(level = "debug", skip(tcx, param_env))]
+fn extract_component_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    ty_seen: &mut UnordSet<Ty<'tcx>>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    // Droppiness does not depend on regions, so let us erase them.
+    let ty = tcx
+        .try_normalize_erasing_regions(
+            ty::TypingEnv { param_env, typing_mode: ty::TypingMode::PostAnalysis },
+            ty,
+        )
+        .unwrap_or(ty);
+
+    let tys = tcx.list_significant_drop_tys(param_env.and(ty));
+    debug!(?ty, "components");
+    let mut out_tys = smallvec![];
+    for ty in tys {
+        if let Some(tys) = true_significant_drop_ty(tcx, ty) {
+            // Some types can be further opened up because the drop is simply delegated
+            for ty in tys {
+                if ty_seen.insert(ty) {
+                    out_tys.extend(extract_component_raw(tcx, param_env, ty, ty_seen));
+                }
+            }
+        } else {
+            if ty_seen.insert(ty) {
+                out_tys.push(ty);
+            }
+        }
+    }
+    out_tys
+}
+
+#[instrument(level = "debug", skip(tcx, param_env))]
+fn extract_component_with_significant_dtor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    let mut tys = extract_component_raw(tcx, param_env, ty, &mut Default::default());
+    let mut deduplicate = FxHashSet::default();
+    tys.retain(|oty| deduplicate.insert(*oty));
+    tys.into_iter().collect()
+}
+
+/// Extract the span of the custom destructor of a type
+/// especially the span of the `impl Drop` header or its entire block
+/// when we are working with current local crate.
+#[instrument(level = "debug", skip(tcx))]
+fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
+    match ty.kind() {
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Error(_)
+        | ty::Str
+        | ty::Never
+        | ty::RawPtr(_, _)
+        | ty::Ref(_, _, _)
+        | ty::FnPtr(_, _)
+        | ty::Tuple(_)
+        | ty::Dynamic(_, _, _)
+        | ty::Alias(_, _)
+        | ty::Bound(_, _)
+        | ty::Pat(_, _)
+        | ty::Placeholder(_)
+        | ty::Infer(_)
+        | ty::Slice(_)
+        | ty::Array(_, _) => None,
+        ty::Adt(adt_def, _) => {
+            let did = adt_def.did();
+            let try_local_did_span = |did: DefId| {
+                if let Some(local) = did.as_local() {
+                    tcx.source_span(local)
+                } else {
+                    tcx.def_span(did)
+                }
+            };
+            let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
+                dtor.did
+            } else if let Some(dtor) = tcx.adt_async_destructor(did) {
+                dtor.future
+            } else {
+                return Some(try_local_did_span(did));
+            };
+            let def_key = tcx.def_key(dtor);
+            let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
+            let parent_did = DefId { index: parent_index, krate: dtor.krate };
+            Some(try_local_did_span(parent_did))
+        }
+        ty::Coroutine(did, _)
+        | ty::CoroutineWitness(did, _)
+        | ty::CoroutineClosure(did, _)
+        | ty::Closure(did, _)
+        | ty::FnDef(did, _)
+        | ty::Foreign(did) => Some(tcx.def_span(did)),
+        ty::Param(_) => None,
+    }
+}
+
+/// Check if a moved place at `idx` is a part of a BID.
+/// The use of this check is that we will consider drops on these
+/// as a drop of the overall BID and, thus, we can exclude it from the diagnosis.
+fn place_descendent_of_bids<'tcx>(
+    mut idx: MovePathIndex,
+    move_data: &MoveData<'tcx>,
+    bids: &UnordSet<&Place<'tcx>>,
+) -> bool {
+    loop {
+        let path = &move_data.move_paths[idx];
+        if bids.contains(&path.place) {
+            return true;
+        }
+        if let Some(parent) = path.parent {
+            idx = parent;
+        } else {
+            return false;
+        }
+    }
+}
+
+/// The core of the lint `tail-expr-drop-order`
+pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) {
+    if matches!(tcx.def_kind(def_id), rustc_hir::def::DefKind::SyntheticCoroutineBody) {
+        // A synthetic coroutine has no HIR body and it is enough to just analyse the original body
+        return;
+    }
+    if body.span.edition().at_least_rust_2024()
+        || tcx.lints_that_dont_need_to_run(()).contains(&lint::LintId::of(TAIL_EXPR_DROP_ORDER))
+    {
+        return;
+    }
+    // ## About BIDs in blocks ##
+    // Track the set of blocks that contain a backwards-incompatible drop (BID)
+    // and, for each block, the vector of locations.
+    //
+    // We group them per-block because they tend to scheduled in the same drop ladder block.
+    let mut bid_per_block = IndexMap::default();
+    let mut bid_places = UnordSet::new();
+    let param_env = tcx.param_env(def_id).with_reveal_all_normalized(tcx);
+    let mut ty_dropped_components = UnordMap::default();
+    for (block, data) in body.basic_blocks.iter_enumerated() {
+        for (statement_index, stmt) in data.statements.iter().enumerate() {
+            if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = &stmt.kind {
+                let ty = place.ty(body, tcx).ty;
+                if ty_dropped_components
+                    .entry(ty)
+                    .or_insert_with(|| extract_component_with_significant_dtor(tcx, param_env, ty))
+                    .is_empty()
+                {
+                    continue;
+                }
+                bid_per_block
+                    .entry(block)
+                    .or_insert(vec![])
+                    .push((Location { block, statement_index }, &**place));
+                bid_places.insert(&**place);
+            }
+        }
+    }
+    if bid_per_block.is_empty() {
+        return;
+    }
+
+    dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(()));
+    let locals_with_user_names = collect_user_names(body);
+    let is_closure_like = tcx.is_closure_like(def_id.to_def_id());
+
+    // Compute the "maybe initialized" information for this body.
+    // When we encounter a DROP of some place P we only care
+    // about the drop if `P` may be initialized.
+    let move_data = MoveData::gather_moves(body, tcx, |_| true);
+    let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data);
+    let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body);
+    let mut block_drop_value_info =
+        IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len());
+    for (&block, candidates) in &bid_per_block {
+        // We will collect drops on locals on paths between BID points to their actual drop locations
+        // into `all_locals_dropped`.
+        let mut all_locals_dropped = ChunkedBitSet::new_empty(move_data.move_paths.len());
+        let mut drop_span = None;
+        for &(_, place) in candidates.iter() {
+            let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len());
+            // ## On detecting change in relative drop order ##
+            // Iterate through each BID-containing block `block`.
+            // If the place `P` targeted by the BID is "maybe initialized",
+            // then search forward to find the actual `DROP(P)` point.
+            // Everything dropped between the BID and the actual drop point
+            // is something whose relative drop order will change.
+            DropsReachable {
+                body,
+                place,
+                drop_span: &mut drop_span,
+                move_data: &move_data,
+                maybe_init: &mut maybe_init,
+                block_drop_value_info: &mut block_drop_value_info,
+                collected_drops: &mut collected_drops,
+                visited: Default::default(),
+            }
+            .visit(block);
+            // Compute the set `all_locals_dropped` of local variables that are dropped
+            // after the BID point but before the current drop point.
+            //
+            // These are the variables whose drop impls will be reordered with respect
+            // to `place`.
+            all_locals_dropped.union(&collected_drops);
+        }
+
+        // We shall now exclude some local bindings for the following cases.
+        {
+            let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size());
+            // We will now do subtraction from the candidate dropped locals, because of the following reasons.
+            for path_idx in all_locals_dropped.iter() {
+                let move_path = &move_data.move_paths[path_idx];
+                let dropped_local = move_path.place.local;
+                // a) A return value _0 will eventually be used
+                // Example:
+                // fn f() -> Droppy {
+                //     let _x = Droppy;
+                //     Droppy
+                // }
+                // _0 holds the literal `Droppy` and rightfully `_x` has to be dropped first
+                if dropped_local == Local::ZERO {
+                    debug!(?dropped_local, "skip return value");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+                // b) If we are analysing a closure, the captures are still dropped last.
+                // This is part of the closure capture lifetime contract.
+                // They are similar to the return value _0 with respect to lifetime rules.
+                if is_closure_like && matches!(dropped_local, ty::CAPTURE_STRUCT_LOCAL) {
+                    debug!(?dropped_local, "skip closure captures");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+                // c) Sometimes we collect places that are projections into the BID locals,
+                // so they are considered dropped now.
+                // Example:
+                // struct NotVeryDroppy(Droppy);
+                // impl Drop for Droppy {..}
+                // fn f() -> NotVeryDroppy {
+                //    let x = NotVeryDroppy(droppy());
+                //    {
+                //        let y: Droppy = x.0;
+                //        NotVeryDroppy(y)
+                //    }
+                // }
+                // `y` takes `x.0`, which invalidates `x` as a complete `NotVeryDroppy`
+                // so there is no point in linting against `x` any more.
+                if place_descendent_of_bids(path_idx, &move_data, &bid_places) {
+                    debug!(?dropped_local, "skip descendent of bids");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+                let observer_ty = move_path.place.ty(body, tcx).ty;
+                // d) The collected local has no custom destructor that passes our ecosystem filter.
+                if ty_dropped_components
+                    .entry(observer_ty)
+                    .or_insert_with(|| {
+                        extract_component_with_significant_dtor(tcx, param_env, observer_ty)
+                    })
+                    .is_empty()
+                {
+                    debug!(?dropped_local, "skip non-droppy types");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+            }
+            // Suppose that all BIDs point into the same local,
+            // we can remove the this local from the observed drops,
+            // so that we can focus our diagnosis more on the others.
+            if candidates.iter().all(|&(_, place)| candidates[0].1.local == place.local) {
+                for path_idx in all_locals_dropped.iter() {
+                    if move_data.move_paths[path_idx].place.local == candidates[0].1.local {
+                        to_exclude.insert(path_idx);
+                    }
+                }
+            }
+            all_locals_dropped.subtract(&to_exclude);
+        }
+        if all_locals_dropped.is_empty() {
+            // No drop effect is observable, so let us move on.
+            continue;
+        }
+
+        // ## The final work to assemble the diagnosis ##
+        // First collect or generate fresh names for local variable bindings and temporary values.
+        let local_names = assign_observables_names(
+            all_locals_dropped
+                .iter()
+                .map(|path_idx| move_data.move_paths[path_idx].place.local)
+                .chain(candidates.iter().map(|(_, place)| place.local)),
+            &locals_with_user_names,
+        );
+
+        let mut lint_root = None;
+        let mut local_labels = vec![];
+        // We now collect the types with custom destructors.
+        for &(_, place) in candidates {
+            let linted_local_decl = &body.local_decls[place.local];
+            let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else {
+                bug!("a name should have been assigned")
+            };
+            let name = name.as_str();
+
+            if lint_root.is_none()
+                && let ClearCrossCrate::Set(data) =
+                    &body.source_scopes[linted_local_decl.source_info.scope].local_data
+            {
+                lint_root = Some(data.lint_root);
+            }
+
+            // Collect spans of the custom destructors.
+            let mut seen_dyn = false;
+            let destructors = ty_dropped_components
+                .get(&linted_local_decl.ty)
+                .unwrap()
+                .iter()
+                .filter_map(|&ty| {
+                    if let Some(span) = ty_dtor_span(tcx, ty) {
+                        Some(DestructorLabel { span, name, dtor_kind: "concrete" })
+                    } else if matches!(ty.kind(), ty::Dynamic(..)) {
+                        if seen_dyn {
+                            None
+                        } else {
+                            seen_dyn = true;
+                            Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" })
+                        }
+                    } else {
+                        None
+                    }
+                })
+                .collect();
+            local_labels.push(LocalLabel {
+                span: linted_local_decl.source_info.span,
+                destructors,
+                name,
+                is_generated_name,
+                is_dropped_first_edition_2024: true,
+            });
+        }
+
+        // Similarly, custom destructors of the observed drops.
+        for path_idx in all_locals_dropped.iter() {
+            let place = &move_data.move_paths[path_idx].place;
+            // We are not using the type of the local because the drop may be partial.
+            let observer_ty = place.ty(body, tcx).ty;
+
+            let observer_local_decl = &body.local_decls[place.local];
+            let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else {
+                bug!("a name should have been assigned")
+            };
+            let name = name.as_str();
+
+            let mut seen_dyn = false;
+            let destructors = extract_component_with_significant_dtor(tcx, param_env, observer_ty)
+                .into_iter()
+                .filter_map(|ty| {
+                    if let Some(span) = ty_dtor_span(tcx, ty) {
+                        Some(DestructorLabel { span, name, dtor_kind: "concrete" })
+                    } else if matches!(ty.kind(), ty::Dynamic(..)) {
+                        if seen_dyn {
+                            None
+                        } else {
+                            seen_dyn = true;
+                            Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" })
+                        }
+                    } else {
+                        None
+                    }
+                })
+                .collect();
+            local_labels.push(LocalLabel {
+                span: observer_local_decl.source_info.span,
+                destructors,
+                name,
+                is_generated_name,
+                is_dropped_first_edition_2024: false,
+            });
+        }
+
+        let span = local_labels[0].span;
+        tcx.emit_node_span_lint(
+            lint::builtin::TAIL_EXPR_DROP_ORDER,
+            lint_root.unwrap_or(CRATE_HIR_ID),
+            span,
+            TailExprDropOrderLint { local_labels, drop_span, _epilogue: () },
+        );
+    }
+}
+
+/// Extract binding names if available for diagnosis
+fn collect_user_names(body: &Body<'_>) -> IndexMap<Local, Symbol> {
+    let mut names = IndexMap::default();
+    for var_debug_info in &body.var_debug_info {
+        if let mir::VarDebugInfoContents::Place(place) = &var_debug_info.value
+            && let Some(local) = place.local_or_deref_local()
+        {
+            names.entry(local).or_insert(var_debug_info.name);
+        }
+    }
+    names
+}
+
+/// Assign names for anonymous or temporary values for diagnosis
+fn assign_observables_names(
+    locals: impl IntoIterator<Item = Local>,
+    user_names: &IndexMap<Local, Symbol>,
+) -> IndexMap<Local, (String, bool)> {
+    let mut names = IndexMap::default();
+    let mut assigned_names = FxHashSet::default();
+    let mut idx = 0u64;
+    let mut fresh_name = || {
+        idx += 1;
+        (format!("#{idx}"), true)
+    };
+    for local in locals {
+        let name = if let Some(name) = user_names.get(&local) {
+            let name = name.as_str();
+            if assigned_names.contains(name) { fresh_name() } else { (name.to_owned(), false) }
+        } else {
+            fresh_name()
+        };
+        assigned_names.insert(name.0.clone());
+        names.insert(local, name);
+    }
+    names
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_tail_expr_drop_order)]
+struct TailExprDropOrderLint<'a> {
+    #[subdiagnostic]
+    local_labels: Vec<LocalLabel<'a>>,
+    #[label(mir_transform_drop_location)]
+    drop_span: Option<Span>,
+    #[note(mir_transform_note_epilogue)]
+    _epilogue: (),
+}
+
+struct LocalLabel<'a> {
+    span: Span,
+    name: &'a str,
+    is_generated_name: bool,
+    is_dropped_first_edition_2024: bool,
+    destructors: Vec<DestructorLabel<'a>>,
+}
+
+/// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order
+impl Subdiagnostic for LocalLabel<'_> {
+    fn add_to_diag_with<
+        G: rustc_errors::EmissionGuarantee,
+        F: rustc_errors::SubdiagMessageOp<G>,
+    >(
+        self,
+        diag: &mut rustc_errors::Diag<'_, G>,
+        f: &F,
+    ) {
+        diag.arg("name", self.name);
+        diag.arg("is_generated_name", self.is_generated_name);
+        diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024);
+        let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into());
+        diag.span_label(self.span, msg);
+        for dtor in self.destructors {
+            dtor.add_to_diag_with(diag, f);
+        }
+        let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into());
+        diag.span_label(self.span, msg);
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[note(mir_transform_tail_expr_dtor)]
+struct DestructorLabel<'a> {
+    #[primary_span]
+    span: Span,
+    dtor_kind: &'static str,
+    name: &'a str,
+}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 237227f5294..ff027680c49 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -5,7 +5,7 @@ use rustc_index::IndexSlice;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
-use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_type_ir::TyKind::*;
 
 use super::simplify::simplify_cfg;
@@ -19,8 +19,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
-
+        let typing_env = body.typing_env(tcx);
         let mut should_cleanup = false;
         for i in 0..body.basic_blocks.len() {
             let bbs = &*body.basic_blocks;
@@ -40,11 +39,11 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
                 _ => continue,
             };
 
-            if SimplifyToIf.simplify(tcx, body, bb_idx, param_env).is_some() {
+            if SimplifyToIf.simplify(tcx, body, bb_idx, typing_env).is_some() {
                 should_cleanup = true;
                 continue;
             }
-            if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() {
+            if SimplifyToExp::default().simplify(tcx, body, bb_idx, typing_env).is_some() {
                 should_cleanup = true;
                 continue;
             }
@@ -65,7 +64,7 @@ trait SimplifyMatch<'tcx> {
         tcx: TyCtxt<'tcx>,
         body: &mut Body<'tcx>,
         switch_bb_idx: BasicBlock,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<()> {
         let bbs = &body.basic_blocks;
         let (discr, targets) = match bbs[switch_bb_idx].terminator().kind {
@@ -74,7 +73,7 @@ trait SimplifyMatch<'tcx> {
         };
 
         let discr_ty = discr.ty(body.local_decls(), tcx);
-        self.can_simplify(tcx, targets, param_env, bbs, discr_ty)?;
+        self.can_simplify(tcx, targets, typing_env, bbs, discr_ty)?;
 
         let mut patch = MirPatch::new(body);
 
@@ -90,7 +89,16 @@ trait SimplifyMatch<'tcx> {
         let parent_end = Location { block: switch_bb_idx, statement_index };
         patch.add_statement(parent_end, StatementKind::StorageLive(discr_local));
         patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr));
-        self.new_stmts(tcx, targets, param_env, &mut patch, parent_end, bbs, discr_local, discr_ty);
+        self.new_stmts(
+            tcx,
+            targets,
+            typing_env,
+            &mut patch,
+            parent_end,
+            bbs,
+            discr_local,
+            discr_ty,
+        );
         patch.add_statement(parent_end, StatementKind::StorageDead(discr_local));
         patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone());
         patch.apply(body);
@@ -104,7 +112,7 @@ trait SimplifyMatch<'tcx> {
         &mut self,
         tcx: TyCtxt<'tcx>,
         targets: &SwitchTargets,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
         discr_ty: Ty<'tcx>,
     ) -> Option<()>;
@@ -113,7 +121,7 @@ trait SimplifyMatch<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         targets: &SwitchTargets,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         patch: &mut MirPatch<'tcx>,
         parent_end: Location,
         bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
@@ -160,7 +168,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
         &mut self,
         tcx: TyCtxt<'tcx>,
         targets: &SwitchTargets,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
         _discr_ty: Ty<'tcx>,
     ) -> Option<()> {
@@ -197,8 +205,8 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
                 ) if lhs_f == lhs_s
                     && f_c.const_.ty().is_bool()
                     && s_c.const_.ty().is_bool()
-                    && f_c.const_.try_eval_bool(tcx, param_env).is_some()
-                    && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {}
+                    && f_c.const_.try_eval_bool(tcx, typing_env).is_some()
+                    && s_c.const_.try_eval_bool(tcx, typing_env).is_some() => {}
 
                 // Otherwise we cannot optimize. Try another block.
                 _ => return None,
@@ -211,7 +219,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
         &self,
         tcx: TyCtxt<'tcx>,
         targets: &SwitchTargets,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         patch: &mut MirPatch<'tcx>,
         parent_end: Location,
         bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
@@ -235,15 +243,15 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
                     StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
                 ) => {
                     // From earlier loop we know that we are dealing with bool constants only:
-                    let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap();
-                    let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap();
+                    let f_b = f_c.const_.try_eval_bool(tcx, typing_env).unwrap();
+                    let s_b = s_c.const_.try_eval_bool(tcx, typing_env).unwrap();
                     if f_b == s_b {
                         // Same value in both blocks. Use statement as is.
                         patch.add_statement(parent_end, f.kind.clone());
                     } else {
                         // Different value between blocks. Make value conditional on switch
                         // condition.
-                        let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
+                        let size = tcx.layout_of(typing_env.as_query_input(discr_ty)).unwrap().size;
                         let const_cmp = Operand::const_from_scalar(
                             tcx,
                             discr_ty,
@@ -363,7 +371,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
         &mut self,
         tcx: TyCtxt<'tcx>,
         targets: &SwitchTargets,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
         discr_ty: Ty<'tcx>,
     ) -> Option<()> {
@@ -388,7 +396,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
             return None;
         }
 
-        let discr_layout = tcx.layout_of(param_env.and(discr_ty)).unwrap();
+        let discr_layout = tcx.layout_of(typing_env.as_query_input(discr_ty)).unwrap();
         let first_stmts = &bbs[first_target].statements;
         let (second_case_val, second_target) = target_iter.next().unwrap();
         let second_stmts = &bbs[second_target].statements;
@@ -414,8 +422,8 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
                     && f_c.const_.ty().is_integral() =>
                 {
                     match (
-                        f_c.const_.try_eval_scalar_int(tcx, param_env),
-                        s_c.const_.try_eval_scalar_int(tcx, param_env),
+                        f_c.const_.try_eval_scalar_int(tcx, typing_env),
+                        s_c.const_.try_eval_scalar_int(tcx, typing_env),
                     ) {
                         (Some(f), Some(s)) if f == s => ExpectedTransformKind::SameByEq {
                             place: lhs_f,
@@ -467,11 +475,11 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
                     ) if lhs_f == lhs_s
                         && s_c.const_.ty() == f_ty
-                        && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(scalar) => {}
+                        && s_c.const_.try_eval_scalar_int(tcx, typing_env) == Some(scalar) => {}
                     (
                         ExpectedTransformKind::Cast { place: lhs_f, ty: f_ty },
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env)
+                    ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, typing_env)
                         && lhs_f == lhs_s
                         && s_c.const_.ty() == f_ty
                         && can_cast(tcx, other_val, discr_layout, f_ty, f) => {}
@@ -487,7 +495,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
         &self,
         _tcx: TyCtxt<'tcx>,
         targets: &SwitchTargets,
-        _param_env: ParamEnv<'tcx>,
+        _typing_env: ty::TypingEnv<'tcx>,
         patch: &mut MirPatch<'tcx>,
         parent_end: Location,
         bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index fa9a6bfcf7c..6be95b1f0f1 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -325,7 +325,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 if let TempState::Defined { location: loc, .. } = self.temps[local]
                     && let Left(statement) =  self.body.stmt_at(loc)
                     && let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign()
-                    && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.param_env)
+                    && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.typing_env)
                     // Determine the type of the thing we are indexing.
                     && let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind()
                     // It's an array; determine its length.
@@ -490,7 +490,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                             // Integer division: the RHS must be a non-zero const.
                             let rhs_val = match rhs {
                                 Operand::Constant(c) => {
-                                    c.const_.try_eval_scalar_int(self.tcx, self.param_env)
+                                    c.const_.try_eval_scalar_int(self.tcx, self.typing_env)
                                 }
                                 _ => None,
                             };
@@ -509,7 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                                         let lhs_val = match lhs {
                                             Operand::Constant(c) => c
                                                 .const_
-                                                .try_eval_scalar_int(self.tcx, self.param_env),
+                                                .try_eval_scalar_int(self.tcx, self.typing_env),
                                             _ => None,
                                         };
                                         let lhs_min = sz.signed_int_min();
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index b11b503e8d4..af438ac2177 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -85,8 +85,8 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
 }
 
 fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
-    let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-    let ssa = SsaLocals::new(tcx, body, param_env);
+    let typing_env = body.typing_env(tcx);
+    let ssa = SsaLocals::new(tcx, body, typing_env);
 
     let mut replacer = compute_replacement(tcx, body, &ssa);
     debug!(?replacer.targets);
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 55394e93a5c..fd49e956f43 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -92,6 +92,7 @@ impl RemoveNoopLandingPads {
                 | StatementKind::AscribeUserType(..)
                 | StatementKind::Coverage(..)
                 | StatementKind::ConstEvalCounter
+                | StatementKind::BackwardIncompatibleDropHint { .. }
                 | StatementKind::Nop => {
                     // These are all noops in a landing pad
                 }
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 20c34a7469e..f786c676e9e 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -1,7 +1,7 @@
 use rustc_abi::FieldIdx;
 use rustc_index::bit_set::ChunkedBitSet;
 use rustc_middle::mir::{Body, TerminatorKind};
-use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, VariantDef};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, VariantDef};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 use rustc_mir_dataflow::{Analysis, MaybeReachable, move_path_children_matching};
@@ -18,8 +18,8 @@ pub(super) struct RemoveUninitDrops;
 
 impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(body.source.def_id());
-        let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env));
+        let typing_env = body.typing_env(tcx);
+        let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, typing_env));
 
         let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
             .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops"))
@@ -40,7 +40,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
 
             let should_keep = is_needs_drop_and_init(
                 tcx,
-                param_env,
+                typing_env,
                 maybe_inits,
                 &move_data,
                 place.ty(body, tcx).ty,
@@ -66,24 +66,24 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
 
 fn is_needs_drop_and_init<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     maybe_inits: &ChunkedBitSet<MovePathIndex>,
     move_data: &MoveData<'tcx>,
     ty: Ty<'tcx>,
     mpi: MovePathIndex,
 ) -> bool {
     // No need to look deeper if the root is definitely uninit or if it has no `Drop` impl.
-    if !maybe_inits.contains(mpi) || !ty.needs_drop(tcx, param_env) {
+    if !maybe_inits.contains(mpi) || !ty.needs_drop(tcx, typing_env) {
         return false;
     }
 
     let field_needs_drop_and_init = |(f, f_ty, mpi)| {
         let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f));
         let Some(mpi) = child else {
-            return Ty::needs_drop(f_ty, tcx, param_env);
+            return Ty::needs_drop(f_ty, tcx, typing_env);
         };
 
-        is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi)
+        is_needs_drop_and_init(tcx, typing_env, maybe_inits, move_data, f_ty, mpi)
     };
 
     // This pass is only needed for const-checking, so it doesn't handle as many cases as
@@ -110,7 +110,7 @@ fn is_needs_drop_and_init<'tcx>(
                     let downcast =
                         move_path_children_matching(move_data, mpi, |x| x.is_downcast_to(vid));
                     let Some(dc_mpi) = downcast else {
-                        return variant_needs_drop(tcx, param_env, args, variant);
+                        return variant_needs_drop(tcx, typing_env, args, variant);
                     };
 
                     dc_mpi
@@ -139,12 +139,12 @@ fn is_needs_drop_and_init<'tcx>(
 
 fn variant_needs_drop<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     args: GenericArgsRef<'tcx>,
     variant: &VariantDef,
 ) -> bool {
     variant.fields.iter().any(|field| {
         let f_ty = field.ty(tcx, args);
-        f_ty.needs_drop(tcx, param_env)
+        f_ty.needs_drop(tcx, typing_env)
     })
 }
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 28925ba1beb..ad62b47a66d 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -16,18 +16,18 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemoveUnneededDrops on {:?}", body.source);
 
-        let did = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(did);
+        let typing_env = body.typing_env(tcx);
         let mut should_simplify = false;
-
         for block in body.basic_blocks.as_mut() {
             let terminator = block.terminator_mut();
             if let TerminatorKind::Drop { place, target, .. } = terminator.kind {
                 let ty = place.ty(&body.local_decls, tcx);
-                if ty.ty.needs_drop(tcx, param_env) {
+                if ty.ty.needs_drop(tcx, typing_env) {
                     continue;
                 }
-                if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {did:?} ")) {
+                if !tcx.consider_optimizing(|| {
+                    format!("RemoveUnneededDrops {:?}", body.source.def_id())
+                }) {
                     continue;
                 }
                 debug!("SUCCESS: replacing `drop` with goto({:?})", target);
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index f13bb1c5993..6fd70fbe9b0 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -21,9 +21,9 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
             return;
         }
 
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         let local_decls = &body.local_decls;
-        let mut replacer = Replacer { tcx, param_env, local_decls };
+        let mut replacer = Replacer { tcx, typing_env, local_decls };
         for var_debug_info in &mut body.var_debug_info {
             replacer.visit_var_debug_info(var_debug_info);
         }
@@ -35,7 +35,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
 
 struct Replacer<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
 }
 
@@ -61,7 +61,7 @@ impl<'tcx> Replacer<'_, 'tcx> {
         if !maybe_zst(ty) {
             return false;
         }
-        let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else {
+        let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(ty)) else {
             return false;
         };
         layout.is_zst()
@@ -125,6 +125,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
             StatementKind::Coverage(_)
             | StatementKind::Intrinsic(_)
             | StatementKind::Nop
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::ConstEvalCounter => None,
         };
         if let Some(place_for_ty) = place_for_ty
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index f3b2f78b31c..587032ee720 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -8,14 +8,16 @@ pub(super) struct RevealAll;
 
 impl<'tcx> crate::MirPass<'tcx> for RevealAll {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-        RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
+        // FIXME(#132279): This is used during the phase transition from analysis
+        // to runtime, so we have to manually specify the correct typing mode.
+        let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
+        RevealAllVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
     }
 }
 
 struct RevealAllVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
@@ -53,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
         // We have to use `try_normalize_erasing_regions` here, since it's
         // possible that we visit impossible-to-satisfy where clauses here,
         // see #91745
-        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) {
+        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.typing_env, constant.const_) {
             constant.const_ = c;
         }
         self.super_const_operand(constant, location);
@@ -64,7 +66,7 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
         // We have to use `try_normalize_erasing_regions` here, since it's
         // possible that we visit impossible-to-satisfy where clauses here,
         // see #91745
-        if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.param_env, *ty) {
+        if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.typing_env, *ty) {
             *ty = t;
         }
     }
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index ffa11f5b213..f16cde7cd4e 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -274,9 +274,9 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
 
     if ty.is_some() {
         let patch = {
-            let param_env = tcx.param_env_reveal_all_normalized(def_id);
+            let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
             let mut elaborator =
-                DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env };
+                DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, typing_env };
             let dropee = tcx.mk_place_deref(dropee_ptr);
             let resume_block = elaborator.patch.resume_block();
             elaborate_drops::elaborate_drop(
@@ -334,7 +334,7 @@ pub(super) struct DropShimElaborator<'a, 'tcx> {
     pub body: &'a Body<'tcx>,
     pub patch: MirPatch<'tcx>,
     pub tcx: TyCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
+    pub typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl fmt::Debug for DropShimElaborator<'_, '_> {
@@ -355,8 +355,8 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
     }
 
     fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
@@ -914,7 +914,7 @@ fn build_call_shim<'tcx>(
 pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
     debug_assert!(tcx.is_constructor(ctor_id));
 
-    let param_env = tcx.param_env_reveal_all_normalized(ctor_id);
+    let typing_env = ty::TypingEnv::post_analysis(tcx, ctor_id);
 
     // Normalize the sig.
     let sig = tcx
@@ -922,7 +922,7 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
         .instantiate_identity()
         .no_bound_vars()
         .expect("LBR in ADT constructor signature");
-    let sig = tcx.normalize_erasing_regions(param_env, sig);
+    let sig = tcx.normalize_erasing_regions(typing_env, sig);
 
     let ty::Adt(adt_def, args) = sig.output().kind() else {
         bug!("unexpected type for ADT ctor {:?}", sig.output());
diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
index f1672272862..139b25be0ab 100644
--- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
+++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
@@ -48,7 +48,7 @@ struct AsyncDestructorCtorShimBuilder<'tcx> {
     self_ty: Option<Ty<'tcx>>,
     span: Span,
     source_info: SourceInfo,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 
     stack: Vec<Operand<'tcx>>,
     last_bb: BasicBlock,
@@ -86,14 +86,14 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
 
         // Usual case: noop() + unwind resume + return
         let mut bbs = IndexVec::with_capacity(3);
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
+        let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
         AsyncDestructorCtorShimBuilder {
             tcx,
             def_id,
             self_ty,
             span,
             source_info,
-            param_env,
+            typing_env,
 
             stack: Vec::with_capacity(Self::MAX_STACK_LEN),
             last_bb: bbs.push(BasicBlockData::new(None)),
@@ -422,7 +422,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
                         statements: Vec::new(),
                         terminator: Some(Terminator {
                             source_info,
-                            kind: if self.locals[local].ty.needs_drop(self.tcx, self.param_env) {
+                            kind: if self.locals[local].ty.needs_drop(self.tcx, self.typing_env) {
                                 TerminatorKind::Drop {
                                     place: local.into(),
                                     target: *top_cleanup_bb,
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 7ed43547e11..4f312ed2aaa 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -523,7 +523,8 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
             }
 
             StatementKind::SetDiscriminant { ref place, variant_index: _ }
-            | StatementKind::Deinit(ref place) => {
+            | StatementKind::Deinit(ref place)
+            | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => {
                 self.visit_lhs(place, location);
             }
         }
@@ -560,6 +561,7 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod
                     StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
 
                     StatementKind::SetDiscriminant { ref place, .. }
+                    | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ }
                     | StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
                     StatementKind::Nop => false,
                     _ => true,
@@ -587,6 +589,20 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
         self.tcx
     }
 
+    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+        if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } =
+            &mut statement.kind
+        {
+            self.visit_local(
+                &mut place.local,
+                PlaceContext::MutatingUse(MutatingUseContext::Store),
+                location,
+            );
+        } else {
+            self.super_statement(statement, location);
+        }
+    }
+
     fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
         *l = self.map[*l].unwrap();
     }
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index e83b4727c48..bea3d0d8557 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -18,14 +18,14 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running SimplifyConstCondition on {:?}", body.source);
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         'blocks: for block in body.basic_blocks_mut() {
             for stmt in block.statements.iter_mut() {
                 // Simplify `assume` of a known value: either a NOP or unreachable.
                 if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind
                     && let NonDivergingIntrinsic::Assume(discr) = intrinsic
                     && let Operand::Constant(ref c) = discr
-                    && let Some(constant) = c.const_.try_eval_bool(tcx, param_env)
+                    && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env)
                 {
                     if constant {
                         stmt.make_nop();
@@ -42,7 +42,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
                 TerminatorKind::SwitchInt {
                     discr: Operand::Constant(ref c), ref targets, ..
                 } => {
-                    let constant = c.const_.try_eval_bits(tcx, param_env);
+                    let constant = c.const_.try_eval_bits(tcx, typing_env);
                     if let Some(constant) = constant {
                         let target = targets.target_for_value(constant);
                         TerminatorKind::Goto { target }
@@ -52,7 +52,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
                 }
                 TerminatorKind::Assert {
                     target, cond: Operand::Constant(ref c), expected, ..
-                } => match c.const_.try_eval_bool(tcx, param_env) {
+                } => match c.const_.try_eval_bool(tcx, typing_env) {
                     Some(v) if v == expected => TerminatorKind::Goto { target },
                     _ => continue,
                 },
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index 26496b7f3fe..b6d80173086 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -37,7 +37,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
         let opts = helper.find_optimizations();
         let mut storage_deads_to_insert = vec![];
         let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![];
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         for opt in opts {
             trace!("SUCCESS: Applying {:?}", opt);
             // replace terminator with a switchInt that switches on the integer directly
@@ -46,7 +46,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
             let new_value = match opt.branch_value_scalar {
                 Scalar::Int(int) => {
                     let layout = tcx
-                        .layout_of(param_env.and(opt.branch_value_ty))
+                        .layout_of(typing_env.as_query_input(opt.branch_value_ty))
                         .expect("if we have an evaluated constant we must know the layout");
                     int.to_bits(layout.size)
                 }
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 53bbb122096..52b9ec1e0a3 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -28,12 +28,12 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
         }
 
         let mut excluded = excluded_locals(body);
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        let typing_env = body.typing_env(tcx);
         loop {
             debug!(?excluded);
-            let escaping = escaping_locals(tcx, param_env, &excluded, body);
+            let escaping = escaping_locals(tcx, typing_env, &excluded, body);
             debug!(?escaping);
-            let replacements = compute_flattening(tcx, param_env, body, escaping);
+            let replacements = compute_flattening(tcx, typing_env, body, escaping);
             debug!(?replacements);
             let all_dead_locals = replace_flattened_locals(tcx, body, replacements);
             if !all_dead_locals.is_empty() {
@@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
 ///   client code.
 fn escaping_locals<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     excluded: &BitSet<Local>,
     body: &Body<'tcx>,
 ) -> BitSet<Local> {
@@ -84,7 +84,7 @@ fn escaping_locals<'tcx>(
                 // niche, so we do not want to automatically exclude it.
                 return false;
             }
-            let Ok(layout) = tcx.layout_of(param_env.and(ty)) else {
+            let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else {
                 // We can't get the layout
                 return true;
             };
@@ -196,7 +196,7 @@ impl<'tcx> ReplacementMap<'tcx> {
 /// The replacement will be done later in `ReplacementVisitor`.
 fn compute_flattening<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     body: &mut Body<'tcx>,
     escaping: BitSet<Local>,
 ) -> ReplacementMap<'tcx> {
@@ -208,7 +208,7 @@ fn compute_flattening<'tcx>(
         }
         let decl = body.local_decls[local].clone();
         let ty = decl.ty;
-        iter_fields(ty, tcx, param_env, |variant, field, field_ty| {
+        iter_fields(ty, tcx, typing_env, |variant, field, field_ty| {
             if variant.is_some() {
                 // Downcasts are currently not supported.
                 return;
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index 84df666e34a..5653aef0aae 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -13,7 +13,7 @@ use rustc_middle::bug;
 use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use tracing::{debug, instrument, trace};
 
 pub(super) struct SsaLocals {
@@ -42,7 +42,7 @@ impl SsaLocals {
     pub(super) fn new<'tcx>(
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
-        param_env: ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
     ) -> SsaLocals {
         let assignment_order = Vec::with_capacity(body.local_decls.len());
 
@@ -80,7 +80,7 @@ impl SsaLocals {
         // have already been marked as non-SSA.
         debug!(?visitor.borrowed_locals);
         for local in visitor.borrowed_locals.iter() {
-            if !body.local_decls[local].ty.is_freeze(tcx, param_env) {
+            if !body.local_decls[local].ty.is_freeze(tcx, typing_env) {
                 visitor.assignments[local] = Set1::Many;
             }
         }
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 3011af4d9d7..57e255b7c32 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -92,9 +92,7 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
 
             let Some(discriminant_ty) = get_switched_on_type(bb_data, tcx, body) else { continue };
 
-            let layout = tcx.layout_of(
-                tcx.param_env_reveal_all_normalized(body.source.def_id()).and(discriminant_ty),
-            );
+            let layout = tcx.layout_of(body.typing_env(tcx).as_query_input(discriminant_ty));
 
             let mut allowed_variants = if let Ok(layout) = layout {
                 // Find allowed variants based on uninhabited.
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index ae4e6ea6a74..1739fdcc9af 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -12,8 +12,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{
-    self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
-    Variance,
+    self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Variance,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_trait_selection::traits::ObligationCtxt;
@@ -47,9 +46,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
         if matches!(body.source.instance, InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..)) {
             return;
         }
+        debug_assert_eq!(self.mir_phase, body.phase);
         let def_id = body.source.def_id();
-        let mir_phase = self.mir_phase;
-        let param_env = mir_phase.param_env(tcx, def_id);
+        let mir_phase = body.phase;
+        let typing_env = body.typing_env(tcx);
         let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) {
             // In this case `AbortUnwindingCalls` haven't yet been executed.
             true
@@ -86,7 +86,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
         cfg_checker.check_cleanup_control_flow();
 
         // Also run the TypeChecker.
-        for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body, body) {
+        for (location, msg) in validate_types(tcx, self.mir_phase, typing_env, body, body) {
             cfg_checker.fail(location, msg);
         }
 
@@ -343,6 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
             | StatementKind::Intrinsic(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
 
@@ -532,12 +533,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
 pub(super) fn validate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
     mir_phase: MirPhase,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     body: &Body<'tcx>,
     caller_body: &Body<'tcx>,
 ) -> Vec<(Location, String)> {
     let mut type_checker =
-        TypeChecker { body, caller_body, tcx, param_env, mir_phase, failures: Vec::new() };
+        TypeChecker { body, caller_body, tcx, typing_env, mir_phase, failures: Vec::new() };
     type_checker.visit_body(body);
     type_checker.failures
 }
@@ -546,7 +547,7 @@ struct TypeChecker<'a, 'tcx> {
     body: &'a Body<'tcx>,
     caller_body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     mir_phase: MirPhase,
     failures: Vec<(Location, String)>,
 }
@@ -582,14 +583,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Variance::Covariant
         };
 
-        crate::util::relate_types(
-            self.tcx,
-            self.body.typing_mode(self.tcx),
-            self.param_env,
-            variance,
-            src,
-            dest,
-        )
+        crate::util::relate_types(self.tcx, self.typing_env, variance, src, dest)
     }
 
     /// Check that the given predicate definitely holds in the param-env of this MIR body.
@@ -608,12 +602,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             return true;
         }
 
-        let infcx = self.tcx.infer_ctxt().build(self.body.typing_mode(self.tcx));
+        let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(Obligation::new(
             self.tcx,
             ObligationCause::dummy(),
-            self.param_env,
+            param_env,
             pred,
         ));
         ocx.select_all_or_error().is_empty()
@@ -630,7 +624,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             if let Operand::Copy(place) = operand {
                 let ty = place.ty(&self.body.local_decls, self.tcx).ty;
 
-                if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
+                if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) {
                     self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}"));
                 }
             }
@@ -802,8 +796,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             ProjectionElem::Subtype(ty) => {
                 if !util::sub_types(
                     self.tcx,
-                    self.body.typing_mode(self.tcx),
-                    self.param_env,
+                    self.typing_env,
                     ty,
                     place_ref.ty(&self.body.local_decls, self.tcx).ty,
                 ) {
@@ -916,7 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     assert!(adt_def.is_union());
                     assert_eq!(idx, FIRST_VARIANT);
                     let dest_ty = self.tcx.normalize_erasing_regions(
-                        self.param_env,
+                        self.typing_env,
                         adt_def.non_enum_variant().fields[field].ty(self.tcx, args),
                     );
                     if let [field] = fields.raw.as_slice() {
@@ -938,7 +931,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     for (src, dest) in std::iter::zip(fields, &variant.fields) {
                         let dest_ty = self
                             .tcx
-                            .normalize_erasing_regions(self.param_env, dest.ty(self.tcx, args));
+                            .normalize_erasing_regions(self.typing_env, dest.ty(self.tcx, args));
                         if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest_ty) {
                             self.fail(location, "adt field has the wrong type");
                         }
@@ -997,7 +990,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             }
 
                             // FIXME: check `Thin` instead of `Sized`
-                            if !in_pointee.is_sized(self.tcx, self.param_env) {
+                            if !in_pointee.is_sized(self.tcx, self.typing_env) {
                                 self.fail(location, "input pointer must be thin");
                             }
                         } else {
@@ -1012,7 +1005,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             if !self.mir_assign_valid_types(metadata_ty, self.tcx.types.usize) {
                                 self.fail(location, "slice metadata must be usize");
                             }
-                        } else if pointee_ty.is_sized(self.tcx, self.param_env) {
+                        } else if pointee_ty.is_sized(self.tcx, self.typing_env) {
                             if metadata_ty != self.tcx.types.unit {
                                 self.fail(location, "metadata for pointer-to-thin must be unit");
                             }
@@ -1301,8 +1294,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
 
                             if !self
                                 .tcx
-                                .normalize_erasing_regions(self.param_env, op_ty)
-                                .is_sized(self.tcx, self.param_env)
+                                .normalize_erasing_regions(self.typing_env, op_ty)
+                                .is_sized(self.tcx, self.typing_env)
                             {
                                 self.fail(
                                     location,
@@ -1311,8 +1304,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             }
                             if !self
                                 .tcx
-                                .normalize_erasing_regions(self.param_env, *target_type)
-                                .is_sized(self.tcx, self.param_env)
+                                .normalize_erasing_regions(self.typing_env, *target_type)
+                                .is_sized(self.tcx, self.typing_env)
                             {
                                 self.fail(
                                     location,
@@ -1353,7 +1346,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                 return;
                             };
 
-                            current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
+                            current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty);
                         }
                         ty::Adt(adt_def, args) => {
                             let Some(field) = adt_def.variant(variant).fields.get(field) else {
@@ -1362,7 +1355,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             };
 
                             let f_ty = field.ty(self.tcx, args);
-                            current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
+                            current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty);
                         }
                         _ => {
                             self.fail(
@@ -1501,6 +1494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             | StatementKind::Coverage(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 429e31b2c88..8ee9ac3df72 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -207,6 +207,7 @@
 
 use std::path::PathBuf;
 
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
@@ -215,7 +216,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
-use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
+use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem};
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Location, MentionedItem, traversal};
 use rustc_middle::query::TyCtxtAt;
@@ -243,16 +244,6 @@ pub(crate) enum MonoItemCollectionStrategy {
     Lazy,
 }
 
-pub(crate) struct UsageMap<'tcx> {
-    // Maps every mono item to the mono items used by it.
-    used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
-
-    // Maps every mono item to the mono items that use it.
-    user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
-}
-
-type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>;
-
 /// The state that is shared across the concurrent threads that are doing collection.
 struct SharedState<'tcx> {
     /// Items that have been or are currently being recursively collected.
@@ -264,22 +255,12 @@ struct SharedState<'tcx> {
     usage_map: MTLock<UsageMap<'tcx>>,
 }
 
-/// See module-level docs on some contect for "mentioned" items.
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum CollectionMode {
-    /// Collect items that are used, i.e., actually needed for codegen.
-    ///
-    /// Which items are used can depend on optimization levels, as MIR optimizations can remove
-    /// uses.
-    UsedItems,
-    /// Collect items that are mentioned. The goal of this mode is that it is independent of
-    /// optimizations: the set of "mentioned" items is computed before optimizations are run.
-    ///
-    /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
-    /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
-    /// might decide to run them before computing mentioned items.) The key property of this set is
-    /// that it is optimization-independent.
-    MentionedItems,
+pub(crate) struct UsageMap<'tcx> {
+    // Maps every mono item to the mono items used by it.
+    used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
+
+    // Maps every mono item to the mono items that use it.
+    user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
 }
 
 impl<'tcx> UsageMap<'tcx> {
@@ -287,19 +268,15 @@ impl<'tcx> UsageMap<'tcx> {
         UsageMap { used_map: Default::default(), user_map: Default::default() }
     }
 
-    fn record_used<'a>(
-        &mut self,
-        user_item: MonoItem<'tcx>,
-        used_items: &'a [Spanned<MonoItem<'tcx>>],
-    ) where
+    fn record_used<'a>(&mut self, user_item: MonoItem<'tcx>, used_items: &'a MonoItems<'tcx>)
+    where
         'tcx: 'a,
     {
-        let used_items: Vec<_> = used_items.iter().map(|item| item.node).collect();
-        for &used_item in used_items.iter() {
+        for used_item in used_items.items() {
             self.user_map.entry(used_item).or_default().push(user_item);
         }
 
-        assert!(self.used_map.insert(user_item, used_items).is_none());
+        assert!(self.used_map.insert(user_item, used_items.items().collect()).is_none());
     }
 
     pub(crate) fn get_user_items(&self, item: MonoItem<'tcx>) -> &[MonoItem<'tcx>] {
@@ -325,6 +302,52 @@ impl<'tcx> UsageMap<'tcx> {
     }
 }
 
+struct MonoItems<'tcx> {
+    // We want a set of MonoItem + Span where trying to re-insert a MonoItem with a different Span
+    // is ignored. Map does that, but it looks odd.
+    items: FxIndexMap<MonoItem<'tcx>, Span>,
+}
+
+impl<'tcx> MonoItems<'tcx> {
+    fn new() -> Self {
+        Self { items: FxIndexMap::default() }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.items.is_empty()
+    }
+
+    fn push(&mut self, item: Spanned<MonoItem<'tcx>>) {
+        // Insert only if the entry does not exist. A normal insert would stomp the first span that
+        // got inserted.
+        self.items.entry(item.node).or_insert(item.span);
+    }
+
+    fn items(&self) -> impl Iterator<Item = MonoItem<'tcx>> + '_ {
+        self.items.keys().cloned()
+    }
+}
+
+impl<'tcx> IntoIterator for MonoItems<'tcx> {
+    type Item = Spanned<MonoItem<'tcx>>;
+    type IntoIter = impl Iterator<Item = Spanned<MonoItem<'tcx>>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.items.into_iter().map(|(item, span)| respan(span, item))
+    }
+}
+
+impl<'tcx> Extend<Spanned<MonoItem<'tcx>>> for MonoItems<'tcx> {
+    fn extend<I>(&mut self, iter: I)
+    where
+        I: IntoIterator<Item = Spanned<MonoItem<'tcx>>>,
+    {
+        for item in iter {
+            self.push(item)
+        }
+    }
+}
+
 /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
 /// post-monomorphization error is encountered during a collection step.
 ///
@@ -404,7 +427,7 @@ fn collect_items_rec<'tcx>(
                 let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
                 // Nested statics have no type.
                 if !nested {
-                    let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+                    let ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized());
                     visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items);
                 }
 
@@ -443,13 +466,9 @@ fn collect_items_rec<'tcx>(
             ));
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                collect_items_of_instance(
-                    tcx,
-                    instance,
-                    &mut used_items,
-                    &mut mentioned_items,
-                    mode,
-                )
+                let (used, mentioned) = tcx.items_of_instance((instance, mode));
+                used_items.extend(used.into_iter().copied());
+                mentioned_items.extend(mentioned.into_iter().copied());
             });
         }
         MonoItem::GlobalAsm(item_id) => {
@@ -617,7 +636,7 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         trace!("monomorphize: self.instance={:?}", self.instance);
         self.instance.instantiate_mir_and_normalize_erasing_regions(
             self.tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             ty::EarlyBinder::bind(value),
         )
     }
@@ -628,12 +647,11 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         constant: &mir::ConstOperand<'tcx>,
     ) -> Option<mir::ConstValue<'tcx>> {
         let const_ = self.monomorphize(constant.const_);
-        let param_env = ty::ParamEnv::reveal_all();
         // Evaluate the constant. This makes const eval failure a collection-time error (rather than
         // a codegen-time error). rustc stops after collection if there was an error, so this
         // ensures codegen never has to worry about failing consts.
         // (codegen relies on this and ICEs will happen if this is violated.)
-        match const_.eval(self.tcx, param_env, constant.span) {
+        match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) {
             Ok(v) => Some(v),
             Err(ErrorHandled::TooGeneric(..)) => span_bug!(
                 constant.span,
@@ -844,9 +862,20 @@ fn visit_fn_use<'tcx>(
 ) {
     if let ty::FnDef(def_id, args) = *ty.kind() {
         let instance = if is_direct_call {
-            ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, source)
+            ty::Instance::expect_resolve(
+                tcx,
+                ty::TypingEnv::fully_monomorphized(),
+                def_id,
+                args,
+                source,
+            )
         } else {
-            match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) {
+            match ty::Instance::resolve_for_fn_ptr(
+                tcx,
+                ty::TypingEnv::fully_monomorphized(),
+                def_id,
+                args,
+            ) {
                 Some(instance) => instance,
                 _ => bug!("failed to resolve instance for {ty}"),
             }
@@ -1005,12 +1034,12 @@ fn find_vtable_types_for_unsizing<'tcx>(
     target_ty: Ty<'tcx>,
 ) -> (Ty<'tcx>, Ty<'tcx>) {
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
-        let param_env = ty::ParamEnv::reveal_all();
+        let typing_env = ty::TypingEnv::fully_monomorphized();
         let type_has_metadata = |ty: Ty<'tcx>| -> bool {
-            if ty.is_sized(tcx.tcx, param_env) {
+            if ty.is_sized(tcx.tcx, typing_env) {
                 return false;
             }
-            let tail = tcx.struct_tail_for_codegen(ty, param_env);
+            let tail = tcx.struct_tail_for_codegen(ty, typing_env);
             match tail.kind() {
                 ty::Foreign(..) => false,
                 ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
@@ -1020,7 +1049,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
         if type_has_metadata(inner_source) {
             (inner_source, inner_target)
         } else {
-            tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, param_env)
+            tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env)
         }
     };
 
@@ -1171,14 +1200,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
 /// Scans the MIR in order to find function calls, closures, and drop-glue.
 ///
 /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
-#[instrument(skip(tcx, used_items, mentioned_items), level = "debug")]
+#[instrument(skip(tcx), level = "debug")]
 fn collect_items_of_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    used_items: &mut MonoItems<'tcx>,
-    mentioned_items: &mut MonoItems<'tcx>,
     mode: CollectionMode,
-) {
+) -> (MonoItems<'tcx>, MonoItems<'tcx>) {
     // This item is getting monomorphized, do mono-time checks.
     tcx.ensure().check_mono_item(instance);
 
@@ -1193,11 +1220,13 @@ fn collect_items_of_instance<'tcx>(
     // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already
     // added to `used_items` in a hash set, which can efficiently query in the
     // `body.mentioned_items` loop below without even having to monomorphize the item.
+    let mut used_items = MonoItems::new();
+    let mut mentioned_items = MonoItems::new();
     let mut used_mentioned_items = Default::default();
     let mut collector = MirUsedCollector {
         tcx,
         body,
-        used_items,
+        used_items: &mut used_items,
         used_mentioned_items: &mut used_mentioned_items,
         instance,
     };
@@ -1212,7 +1241,7 @@ fn collect_items_of_instance<'tcx>(
     // them errors.
     for const_op in body.required_consts() {
         if let Some(val) = collector.eval_constant(const_op) {
-            collect_const_value(tcx, val, mentioned_items);
+            collect_const_value(tcx, val, &mut mentioned_items);
         }
     }
 
@@ -1221,9 +1250,23 @@ fn collect_items_of_instance<'tcx>(
     for item in body.mentioned_items() {
         if !collector.used_mentioned_items.contains(&item.node) {
             let item_mono = collector.monomorphize(item.node);
-            visit_mentioned_item(tcx, &item_mono, item.span, mentioned_items);
+            visit_mentioned_item(tcx, &item_mono, item.span, &mut mentioned_items);
         }
     }
+
+    (used_items, mentioned_items)
+}
+
+fn items_of_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (instance, mode): (Instance<'tcx>, CollectionMode),
+) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) {
+    let (used_items, mentioned_items) = collect_items_of_instance(tcx, instance, mode);
+
+    let used_items = tcx.arena.alloc_from_iter(used_items);
+    let mentioned_items = tcx.arena.alloc_from_iter(mentioned_items);
+
+    (used_items, mentioned_items)
 }
 
 /// `item` must be already monomorphized.
@@ -1237,8 +1280,13 @@ fn visit_mentioned_item<'tcx>(
     match *item {
         MentionedItem::Fn(ty) => {
             if let ty::FnDef(def_id, args) = *ty.kind() {
-                let instance =
-                    Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, span);
+                let instance = Instance::expect_resolve(
+                    tcx,
+                    ty::TypingEnv::fully_monomorphized(),
+                    def_id,
+                    args,
+                    span,
+                );
                 // `visit_instance_use` was written for "used" item collection but works just as well
                 // for "mentioned" item collection.
                 // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
@@ -1304,7 +1352,7 @@ fn collect_const_value<'tcx>(
 #[instrument(skip(tcx, mode), level = "debug")]
 fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoItem<'_>> {
     debug!("collecting roots");
-    let mut roots = Vec::new();
+    let mut roots = MonoItems::new();
 
     {
         let entry_fn = tcx.entry_fn(());
@@ -1454,13 +1502,13 @@ impl<'v> RootCollector<'_, 'v> {
         // regions must appear in the argument
         // listing.
         let main_ret_ty = self.tcx.normalize_erasing_regions(
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             main_ret_ty.no_bound_vars().unwrap(),
         );
 
         let start_instance = Instance::expect_resolve(
             self.tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             start_def_id,
             self.tcx.mk_args(&[main_ret_ty.into()]),
             DUMMY_SP,
@@ -1518,8 +1566,8 @@ fn create_mono_items_for_default_impls<'tcx>(
         return;
     }
 
-    let param_env = ty::ParamEnv::reveal_all();
-    let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
+    let typing_env = ty::TypingEnv::fully_monomorphized();
+    let trait_ref = tcx.normalize_erasing_regions(typing_env, trait_ref);
     let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
     for method in tcx.provided_trait_methods(trait_ref.def_id) {
         if overridden_methods.contains_key(&method.def_id) {
@@ -1534,7 +1582,7 @@ fn create_mono_items_for_default_impls<'tcx>(
         // only has lifetime generic parameters. This is validated by calling
         // `own_requires_monomorphization` on both the impl and method.
         let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params);
-        let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP);
+        let instance = ty::Instance::expect_resolve(tcx, typing_env, method.def_id, args, DUMMY_SP);
 
         let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
         if mono_item.node.is_instantiable(tcx) && tcx.should_codegen_locally(instance) {
@@ -1596,4 +1644,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
 
 pub(crate) fn provide(providers: &mut Providers) {
     providers.hooks.should_codegen_locally = should_codegen_locally;
+    providers.items_of_instance = items_of_instance;
 }
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 0cfc4371db5..0f08930fb4c 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(array_windows)]
 #![feature(file_buffered)]
 #![feature(if_let_guard)]
+#![feature(impl_trait_in_assoc_type)]
 #![feature(let_chains)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
@@ -34,7 +35,9 @@ fn custom_coerce_unsize_info<'tcx>(
         [source_ty, target_ty],
     );
 
-    match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
+    match tcx
+        .codegen_select_candidate(ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref))
+    {
         Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
             impl_def_id,
             ..
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index d53595929e7..30e634d8252 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -3,7 +3,7 @@
 use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::mir::{self, traversal};
 use rustc_middle::ty::inherent::*;
-use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
 use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
 use rustc_span::def_id::DefId;
 use rustc_span::{DUMMY_SP, Span, Symbol};
@@ -36,9 +36,7 @@ fn do_check_abi<'tcx>(
     target_feature_def: DefId,
     mut emit_err: impl FnMut(Option<&'static str>),
 ) {
-    let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else {
-        return;
-    };
+    let feature_def = tcx.sess.target.features_for_correct_vector_abi();
     let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);
     for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
         let size = arg_abi.layout.size;
@@ -64,8 +62,9 @@ fn do_check_abi<'tcx>(
 /// Checks that the ABI of a given instance of a function does not contain vector-passed arguments
 /// or return values for which the corresponding target feature is not enabled.
 fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
-    let param_env = ParamEnv::reveal_all();
-    let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else {
+    let typing_env = ty::TypingEnv::fully_monomorphized();
+    let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
+    else {
         // An error will be reported during codegen if we cannot determine the ABI of this
         // function.
         return;
@@ -102,18 +101,18 @@ fn check_call_site_abi<'tcx>(
         // "Rust" ABI never passes arguments in vector registers.
         return;
     }
-    let param_env = ParamEnv::reveal_all();
+    let typing_env = ty::TypingEnv::fully_monomorphized();
     let callee_abi = match *callee.kind() {
         ty::FnPtr(..) => {
-            tcx.fn_abi_of_fn_ptr(param_env.and((callee.fn_sig(tcx), ty::List::empty())))
+            tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((callee.fn_sig(tcx), ty::List::empty())))
         }
         ty::FnDef(def_id, args) => {
             // Intrinsics are handled separately by the compiler.
             if tcx.intrinsic(def_id).is_some() {
                 return;
             }
-            let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, DUMMY_SP);
-            tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty())))
+            let instance = ty::Instance::expect_resolve(tcx, typing_env, def_id, args, DUMMY_SP);
+            tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
         }
         _ => {
             panic!("Invalid function call");
@@ -153,7 +152,7 @@ fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &m
                 let callee_ty = func.ty(body, tcx);
                 let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
                     tcx,
-                    ty::ParamEnv::reveal_all(),
+                    ty::TypingEnv::fully_monomorphized(),
                     ty::EarlyBinder::bind(callee_ty),
                 );
                 check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
index 7f04bdf46f1..438d49fd7fb 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
@@ -61,7 +61,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> {
         trace!("monomorphize: self.instance={:?}", self.instance);
         self.instance.instantiate_mir_and_normalize_erasing_regions(
             self.tcx,
-            ty::ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             ty::EarlyBinder::bind(value),
         )
     }
@@ -128,7 +128,9 @@ impl<'tcx> MoveCheckVisitor<'tcx> {
     ) -> Option<Size> {
         let ty = operand.ty(self.body, self.tcx);
         let ty = self.monomorphize(ty);
-        let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else {
+        let Ok(layout) =
+            self.tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
+        else {
             return None;
         };
         if layout.size.bytes_usize() > limit.0 {
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index e2a6d392ca0..7240cfce0f7 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -666,7 +666,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
                     // This is a method within an impl, find out what the self-type is:
                     let impl_self_ty = tcx.instantiate_and_normalize_erasing_regions(
                         instance.args,
-                        ty::ParamEnv::reveal_all(),
+                        ty::TypingEnv::fully_monomorphized(),
                         tcx.type_of(impl_def_id),
                     );
                     if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
@@ -1319,5 +1319,20 @@ pub(crate) fn provide(providers: &mut Providers) {
             .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
     };
 
+    providers.size_estimate = |tcx, instance| {
+        match instance.def {
+            // "Normal" functions size estimate: the number of
+            // statements, plus one for the terminator.
+            InstanceKind::Item(..)
+            | InstanceKind::DropGlue(..)
+            | InstanceKind::AsyncDropGlueCtorShim(..) => {
+                let mir = tcx.instance_mir(instance.def);
+                mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
+            }
+            // Other compiler-generated shims size estimate: 1
+            _ => 1,
+        }
+    };
+
     collector::provide(providers);
 }
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index 093a697beeb..deb4ab433bf 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -22,29 +22,29 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
     let typeck_results = tcx.typeck(closure_def_id);
 
     if typeck_results.closure_size_eval.contains_key(&closure_def_id) {
-        let param_env = ty::ParamEnv::reveal_all();
+        let typing_env = ty::TypingEnv::fully_monomorphized();
 
         let ClosureSizeProfileData { before_feature_tys, after_feature_tys } =
             typeck_results.closure_size_eval[&closure_def_id];
 
         let before_feature_tys = tcx.instantiate_and_normalize_erasing_regions(
             closure_instance.args,
-            param_env,
+            typing_env,
             ty::EarlyBinder::bind(before_feature_tys),
         );
         let after_feature_tys = tcx.instantiate_and_normalize_erasing_regions(
             closure_instance.args,
-            param_env,
+            typing_env,
             ty::EarlyBinder::bind(after_feature_tys),
         );
 
         let new_size = tcx
-            .layout_of(param_env.and(after_feature_tys))
+            .layout_of(typing_env.as_query_input(after_feature_tys))
             .map(|l| format!("{:?}", l.size.bytes()))
             .unwrap_or_else(|e| format!("Failed {e:?}"));
 
         let old_size = tcx
-            .layout_of(param_env.and(before_feature_tys))
+            .layout_of(typing_env.as_query_input(before_feature_tys))
             .map(|l| format!("{:?}", l.size.bytes()))
             .unwrap_or_else(|e| format!("Failed {e:?}"));
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index ebf7372926f..545ab15b945 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -102,7 +102,7 @@ where
 
     /// Assemble additional assumptions for an alias that are not included
     /// in the item bounds of the alias. For now, this is limited to the
-    /// `implied_const_bounds` for an associated type.
+    /// `explicit_implied_const_bounds` for an associated type.
     fn consider_additional_alias_assumptions(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
@@ -159,13 +159,6 @@ where
         goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution>;
 
-    /// A type is `PointerLike` if we can compute its layout, and that layout
-    /// matches the layout of `usize`.
-    fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution>;
-
     /// A type is a `FnPtr` if it is of `FnPtr` type.
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, D>,
@@ -449,9 +442,6 @@ where
                         ty::ClosureKind::FnOnce,
                     )
                 }
-                Some(TraitSolverLangItem::PointerLike) => {
-                    G::consider_builtin_pointer_like_candidate(self, goal)
-                }
                 Some(TraitSolverLangItem::FnPtrTrait) => {
                     G::consider_builtin_fn_ptr_trait_candidate(self, goal)
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 5c1a7852dc0..a56febec48c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -633,6 +633,76 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
     )
 }
 
+/// This duplicates `extract_tupled_inputs_and_output_from_callable` but needs
+/// to return different information (namely, the def id and args) so that we can
+/// create const conditions.
+///
+/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable`
+/// would be wasteful.
+pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
+    cx: I,
+    self_ty: I::Ty,
+) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> {
+    match self_ty.kind() {
+        ty::FnDef(def_id, args) => {
+            let sig = cx.fn_sig(def_id);
+            if sig.skip_binder().is_fn_trait_compatible()
+                && !cx.has_target_features(def_id)
+                && cx.fn_is_const(def_id)
+            {
+                Ok((
+                    sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())),
+                    def_id,
+                    args,
+                ))
+            } else {
+                return Err(NoSolution);
+            }
+        }
+        // `FnPtr`s are not const for now.
+        ty::FnPtr(..) => {
+            return Err(NoSolution);
+        }
+        // `Closure`s are not const for now.
+        ty::Closure(..) => {
+            return Err(NoSolution);
+        }
+        // `CoroutineClosure`s are not const for now.
+        ty::CoroutineClosure(..) => {
+            return Err(NoSolution);
+        }
+
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Adt(_, _)
+        | ty::Foreign(_)
+        | ty::Str
+        | ty::Array(_, _)
+        | ty::Slice(_)
+        | ty::RawPtr(_, _)
+        | ty::Ref(_, _, _)
+        | ty::Dynamic(_, _, _)
+        | ty::Coroutine(_, _)
+        | ty::CoroutineWitness(..)
+        | ty::Never
+        | ty::Tuple(_)
+        | ty::Pat(_, _)
+        | ty::Alias(_, _)
+        | ty::Param(_)
+        | ty::Placeholder(..)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+        | ty::Error(_) => return Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            panic!("unexpected type `{self_ty:?}`")
+        }
+    }
+}
+
 /// Assemble a list of predicates that would be present on a theoretical
 /// user impl for an object type. These predicates must be checked any time
 /// we assemble a built-in object candidate for an object type, since they
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 0912e5effa6..603a68eb890 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -3,15 +3,15 @@
 
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
+use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::{self as ty, Interner, elaborate};
 use tracing::instrument;
 
-use super::assembly::Candidate;
+use super::assembly::{Candidate, structural_traits};
 use crate::delegate::SolverDelegate;
-use crate::solve::assembly::{self};
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution,
-    QueryResult,
+    QueryResult, assembly,
 };
 
 impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I>
@@ -84,12 +84,9 @@ where
         let cx = ecx.cx();
         let mut candidates = vec![];
 
-        // FIXME(const_trait_impl): We elaborate here because the implied const bounds
-        // aren't necessarily elaborated. We probably should prefix this query
-        // with `explicit_`...
         for clause in elaborate::elaborate(
             cx,
-            cx.implied_const_bounds(alias_ty.def_id)
+            cx.explicit_implied_const_bounds(alias_ty.def_id)
                 .iter_instantiated(cx, alias_ty.args)
                 .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
         ) {
@@ -142,7 +139,7 @@ where
             ty::ImplPolarity::Positive => {}
         };
 
-        if !cx.is_const_impl(impl_def_id) {
+        if !cx.impl_is_const(impl_def_id) {
             return Err(NoSolution);
         }
 
@@ -207,14 +204,7 @@ where
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution> {
-        todo!("Copy/Clone is not yet const")
-    }
-
-    fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("PointerLike is not const")
+        Err(NoSolution)
     }
 
     fn consider_builtin_fn_ptr_trait_candidate(
@@ -225,11 +215,48 @@ where
     }
 
     fn consider_builtin_fn_trait_candidates(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
+        ecx: &mut EvalCtxt<'_, D>,
+        goal: Goal<I, Self>,
         _kind: rustc_type_ir::ClosureKind,
     ) -> Result<Candidate<I>, NoSolution> {
-        todo!("Fn* are not yet const")
+        let cx = ecx.cx();
+
+        let self_ty = goal.predicate.self_ty();
+        let (inputs_and_output, def_id, args) =
+            structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
+
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
+        let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| {
+            ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
+        });
+        let requirements = cx
+            .const_conditions(def_id)
+            .iter_instantiated(cx, args)
+            .map(|trait_ref| {
+                (
+                    GoalSource::ImplWhereBound,
+                    goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
+                )
+            })
+            .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
+
+        let pred = inputs_and_output
+            .map_bound(|(inputs, _)| {
+                ty::TraitRef::new(cx, goal.predicate.def_id(), [
+                    goal.predicate.self_ty(),
+                    Ty::new_tup(cx, inputs.as_slice()),
+                ])
+            })
+            .to_host_effect_clause(cx, goal.predicate.constness);
+
+        Self::probe_and_consider_implied_clause(
+            ecx,
+            CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
+            goal,
+            pred,
+            requirements,
+        )
     }
 
     fn consider_builtin_async_fn_trait_candidates(
@@ -314,7 +341,7 @@ where
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("Destruct is not const")
+        Err(NoSolution)
     }
 
     fn consider_builtin_transmute_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 129744b4db7..6b407640426 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -363,13 +363,6 @@ where
         panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`PointerLike` does not have an associated type: {:?}", goal);
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         _ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
@@ -394,6 +387,9 @@ where
                     return ecx.forced_ambiguity(MaybeCause::Ambiguity);
                 }
             };
+
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
             ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
         });
@@ -408,8 +404,6 @@ where
             })
             .upcast(cx);
 
-        // A built-in `Fn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
@@ -438,6 +432,9 @@ where
                 goal_kind,
                 env_region,
             )?;
+
+        // A built-in `AsyncFn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
             |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
                 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output_ty])
@@ -494,8 +491,6 @@ where
             )
             .upcast(cx);
 
-        // A built-in `AsyncFn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
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 df4f0ffdd57..ce16258d180 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -248,28 +248,6 @@ where
         )
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        let cx = ecx.cx();
-        // But if there are inference variables, we have to wait until it's resolved.
-        if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() {
-            return ecx.forced_ambiguity(MaybeCause::Ambiguity);
-        }
-
-        if cx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) {
-            ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
-                .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
-        } else {
-            Err(NoSolution)
-        }
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
@@ -322,6 +300,9 @@ where
                     return ecx.forced_ambiguity(MaybeCause::Ambiguity);
                 }
             };
+
+        // A built-in `Fn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
             ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
         });
@@ -331,8 +312,6 @@ where
                 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
             })
             .upcast(cx);
-        // A built-in `Fn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
@@ -360,6 +339,9 @@ where
                 // This region doesn't matter because we're throwing away the coroutine type
                 Region::new_static(cx),
             )?;
+
+        // A built-in `AsyncFn` impl only holds if the output is sized.
+        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
             |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
                 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [
@@ -376,8 +358,6 @@ where
                 ])
             })
             .upcast(cx);
-        // A built-in `AsyncFn` impl only holds if the output is sized.
-        // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
             ecx,
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 7ec4ad6dc35..37eb463cba6 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -650,8 +650,9 @@ pub(crate) struct LeftArrowOperator {
 #[diag(parse_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 226de65445c..5023e83bd67 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -213,7 +213,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
                     let ident = Symbol::intern(lifetime_name);
                     token::Lifetime(ident, IdentIsRaw::No)
                 }
-                rustc_lexer::TokenKind::InvalidIdent | rustc_lexer::TokenKind::InvalidPrefix
+                rustc_lexer::TokenKind::InvalidIdent
                     // Do not recover an identifier with emoji if the codepoint is a confusable
                     // with a recoverable substitution token, like `âž–`.
                     if !UNICODE_ARRAY.iter().any(|&(c, _, _)| {
@@ -359,8 +359,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
                 rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
 
                 rustc_lexer::TokenKind::Unknown
-                | rustc_lexer::TokenKind::InvalidIdent
-                | rustc_lexer::TokenKind::InvalidPrefix => {
+                | rustc_lexer::TokenKind::InvalidIdent => {
                     // Don't emit diagnostics for sequences of the same invalid token
                     if swallow_next_invalid > 0 {
                         swallow_next_invalid -= 1;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0ac6133e828..0012db471ef 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2683,6 +2683,13 @@ impl<'a> Parser<'a> {
                 //            ^^
                 //     }
                 //
+                // We account for macro calls that were meant as conditions as well.
+                //
+                //     if ... {
+                //     } else if macro! { foo bar } {
+                //            ^^
+                //     }
+                //
                 // If $cond is "statement-like" such as ExprKind::While then we
                 // want to suggest wrapping in braces.
                 //
@@ -2693,7 +2700,9 @@ impl<'a> Parser<'a> {
                 //     }
                 //     ^
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
-                        && classify::expr_requires_semi_to_be_stmt(&cond) =>
+                        && (classify::expr_requires_semi_to_be_stmt(&cond)
+                            || matches!(cond.kind, ExprKind::MacCall(..)))
+                    =>
                 {
                     self.dcx().emit_err(errors::ExpectedElseBlock {
                         first_tok_span,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 6b4e2d0f4e2..fddbf5896ad 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -77,18 +77,35 @@ impl<'a> Parser<'a> {
         if !self.eat(term) {
             let token_str = super::token_descr(&self.token);
             if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
+                let is_let = self.token.is_keyword(kw::Let);
+                let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut));
+                let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let);
+
                 let msg = format!("expected item, found {token_str}");
                 let mut err = self.dcx().struct_span_err(self.token.span, msg);
-                let span = self.token.span;
-                if self.is_kw_followed_by_ident(kw::Let) {
-                    err.span_label(
-                        span,
-                        "consider using `const` or `static` instead of `let` for global variables",
-                    );
+
+                let label = if is_let {
+                    "`let` cannot be used for global variables"
                 } else {
-                    err.span_label(span, "expected item")
-                        .note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
+                    "expected item"
                 };
+                err.span_label(self.token.span, label);
+
+                if is_let {
+                    if is_let_mut {
+                        err.help("consider using `static` and a `Mutex` instead of `let mut`");
+                    } else if let_has_ident {
+                        err.span_suggestion_short(
+                            self.token.span,
+                            "consider using `static` or `const` instead of `let`",
+                            "static",
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.help("consider using `static` or `const` instead of `let`");
+                    }
+                }
+                err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
                 return Err(err);
             }
         }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 50a8b6542df..042ee96bbe8 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -641,9 +641,10 @@ impl<'a> Parser<'a> {
             return true;
         }
 
+        // Do an ASCII case-insensitive match, because all keywords are ASCII.
         if case == Case::Insensitive
             && let Some((ident, IdentIsRaw::No)) = self.token.ident()
-            && ident.as_str().to_lowercase() == kw.as_str().to_lowercase()
+            && ident.as_str().eq_ignore_ascii_case(kw.as_str())
         {
             true
         } else {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 3546e5b0f04..c4326427f67 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -685,7 +685,7 @@ impl<'a> Parser<'a> {
             self.bump();
             // Trim extra space after the `let`
             let span = lo.with_hi(self.token.span.lo());
-            self.dcx().emit_err(RemoveLet { span });
+            self.dcx().emit_err(RemoveLet { span: lo, suggestion: span });
             lo = self.token.span;
         }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index b7cdae3e3e1..190cd9ed061 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -475,6 +475,7 @@ impl<'a> Parser<'a> {
     }
 
     fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
+        let prev = self.prev_token.span;
         let sp = self.token.span;
         let mut e = self.dcx().struct_span_err(sp, msg);
         let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
@@ -514,8 +515,97 @@ impl<'a> Parser<'a> {
                 } else {
                     stmt.span
                 };
+                self.suggest_fixes_misparsed_for_loop_head(
+                    &mut e,
+                    prev.between(sp),
+                    stmt_span,
+                    &stmt.kind,
+                );
+            }
+            Err(e) => {
+                self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
+                e.cancel();
+            }
+            _ => {}
+        }
+        e.span_label(sp, "expected `{`");
+        e
+    }
+
+    fn suggest_fixes_misparsed_for_loop_head(
+        &self,
+        e: &mut Diag<'_>,
+        between: Span,
+        stmt_span: Span,
+        stmt_kind: &StmtKind,
+    ) {
+        match (&self.token.kind, &stmt_kind) {
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Call(..) = expr.kind =>
+            {
+                // for _ in x y() {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a method call",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Field(..) = expr.kind =>
+            {
+                // for _ in x y.z {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a field access",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Struct(expr) = &expr.kind
+                    && let None = expr.qself
+                    && expr.path.segments.len() == 1 =>
+            {
+                // This is specific to "mistyped `if` condition followed by empty body"
+                //
+                // for _ in x y {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a field access",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Lit(lit) = expr.kind
+                    && let None = lit.suffix
+                    && let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
+            {
+                // for _ in x 0 {}
+                // for _ in x 0.0 {}
+                e.span_suggestion_verbose(
+                    between,
+                    format!("you might have meant to write a field access"),
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Loop(..)
+                | ExprKind::If(..)
+                | ExprKind::While(..)
+                | ExprKind::Match(..)
+                | ExprKind::ForLoop { .. }
+                | ExprKind::TryBlock(..)
+                | ExprKind::Ret(..)
+                | ExprKind::Closure(..)
+                | ExprKind::Struct(..)
+                | ExprKind::Try(..) = expr.kind =>
+            {
+                // These are more likely to have been meant as a block body.
                 e.multipart_suggestion(
-                    "try placing this code inside a block",
+                    "you might have meant to write this as part of a block",
                     vec![
                         (stmt_span.shrink_to_lo(), "{ ".to_string()),
                         (stmt_span.shrink_to_hi(), " }".to_string()),
@@ -524,14 +614,19 @@ impl<'a> Parser<'a> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            Err(e) => {
-                self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
-                e.cancel();
+            (token::OpenDelim(Delimiter::Brace), _) => {}
+            (_, _) => {
+                e.multipart_suggestion(
+                    "you might have meant to write this as part of a block",
+                    vec![
+                        (stmt_span.shrink_to_lo(), "{ ".to_string()),
+                        (stmt_span.shrink_to_hi(), " }".to_string()),
+                    ],
+                    // Speculative; has been misleading in the past (#46836).
+                    Applicability::MaybeIncorrect,
+                );
             }
-            _ => {}
         }
-        e.span_label(sp, "expected `{`");
-        e
     }
 
     fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index b1267562f7b..4db8584b884 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -59,9 +59,9 @@ fn unwrap_fn_abi<'tcx>(
 }
 
 fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
-    let param_env = tcx.param_env(item_def_id);
+    let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
     let args = GenericArgs::identity_for_item(tcx, item_def_id);
-    let instance = match Instance::try_resolve(tcx, param_env, item_def_id.into(), args) {
+    let instance = match Instance::try_resolve(tcx, typing_env, item_def_id.into(), args) {
         Ok(Some(instance)) => instance,
         Ok(None) => {
             // Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
@@ -75,7 +75,9 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
         Err(_guaranteed) => return,
     };
     let abi = unwrap_fn_abi(
-        tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))),
+        tcx.fn_abi_of_instance(
+            typing_env.as_query_input((instance, /* extra_args */ ty::List::empty())),
+        ),
         tcx,
         item_def_id,
     );
@@ -117,10 +119,10 @@ fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx,
 }
 
 fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
-    let param_env = tcx.param_env(item_def_id);
+    let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
     let span = tcx.def_span(item_def_id);
-    if !ensure_wf(tcx, param_env, ty, item_def_id, span) {
+    if !ensure_wf(tcx, typing_env, ty, item_def_id, span) {
         return;
     }
     let meta_items = attr.meta_item_list().unwrap_or_default();
@@ -134,10 +136,10 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
                     );
                 };
                 let abi = unwrap_fn_abi(
-                    tcx.fn_abi_of_fn_ptr(
-                        param_env
-                            .and((sig_tys.with(*hdr), /* extra_args */ ty::List::empty())),
-                    ),
+                    tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
+                        sig_tys.with(*hdr),
+                        /* extra_args */ ty::List::empty(),
+                    ))),
                     tcx,
                     item_def_id,
                 );
@@ -165,10 +167,10 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
                     );
                 };
                 let abi1 = unwrap_fn_abi(
-                    tcx.fn_abi_of_fn_ptr(
-                        param_env
-                            .and((sig_tys1.with(*hdr1), /* extra_args */ ty::List::empty())),
-                    ),
+                    tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
+                        sig_tys1.with(*hdr1),
+                        /* extra_args */ ty::List::empty(),
+                    ))),
                     tcx,
                     item_def_id,
                 );
@@ -179,10 +181,10 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
                     );
                 };
                 let abi2 = unwrap_fn_abi(
-                    tcx.fn_abi_of_fn_ptr(
-                        param_env
-                            .and((sig_tys2.with(*hdr2), /* extra_args */ ty::List::empty())),
-                    ),
+                    tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
+                        sig_tys2.with(*hdr2),
+                        /* extra_args */ ty::List::empty(),
+                    ))),
                     tcx,
                     item_def_id,
                 );
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 836511325f4..87069e0b057 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -162,6 +162,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     self.check_rustc_std_internal_symbol(attr, span, target)
                 }
                 [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
+                [sym::rustc_as_ptr, ..] => {
+                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                }
                 [sym::rustc_never_returns_null_ptr, ..] => {
                     self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                 }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index b1db66fa52d..ecf8d34ad84 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -273,7 +273,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             data.get(expr.hir_id).expect("no offset_of_data for offset_of");
 
         let body_did = self.typeck_results().hir_owner.to_def_id();
-        let param_env = self.tcx.param_env(body_did);
+        let typing_env = ty::TypingEnv::non_body_analysis(self.tcx, body_did);
 
         let mut current_ty = container;
 
@@ -285,13 +285,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     self.insert_def_id(field.did);
                     let field_ty = field.ty(self.tcx, args);
 
-                    current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty);
+                    current_ty = self.tcx.normalize_erasing_regions(typing_env, field_ty);
                 }
                 // we don't need to mark tuple fields as live,
                 // but we may need to mark subfields
                 ty::Tuple(tys) => {
                     current_ty =
-                        self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]);
+                        self.tcx.normalize_erasing_regions(typing_env, tys[field.as_usize()]);
                 }
                 _ => span_bug!(expr.span, "named field access on non-ADT"),
             }
@@ -944,7 +944,10 @@ impl<'tcx> DeadVisitor<'tcx> {
         if is_positional
             && self
                 .tcx
-                .layout_of(self.tcx.param_env(field.did).and(field_type))
+                .layout_of(
+                    ty::TypingEnv::non_body_analysis(self.tcx, field.did)
+                        .as_query_input(field_type),
+                )
                 .map_or(true, |layout| layout.is_zst())
         {
             return ShouldWarnAboutField::No;
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 55fdbac8ad6..db34189be2a 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -126,6 +126,7 @@ impl<'k> StatCollector<'k> {
         });
 
         let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
+        let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum();
 
         eprintln!("{prefix} {title}");
         eprintln!(
@@ -167,7 +168,13 @@ impl<'k> StatCollector<'k> {
             }
         }
         eprintln!("{prefix} ----------------------------------------------------------------");
-        eprintln!("{} {:<18}{:>10}", prefix, "Total", to_readable_str(total_size));
+        eprintln!(
+            "{} {:<18}{:>10}        {:>14}",
+            prefix,
+            "Total",
+            to_readable_str(total_size),
+            to_readable_str(total_count),
+        );
         eprintln!("{prefix}");
     }
 }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 986dce5b56d..bb90b5a1e31 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -2,10 +2,9 @@ use rustc_abi::{HasDataLayout, TargetDataLayout};
 use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::infer::canonical::ir::TypingMode;
 use rustc_middle::span_bug;
-use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers};
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
@@ -39,11 +38,13 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
 
 pub fn ensure_wf<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
     def_id: LocalDefId,
     span: Span,
 ) -> bool {
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+    let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
     let pred = ty::ClauseKind::WellFormed(ty.into());
     let obligation = traits::Obligation::new(
         tcx,
@@ -55,8 +56,6 @@ pub fn ensure_wf<'tcx>(
         param_env,
         pred,
     );
-    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
-    let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
     ocx.register_obligation(obligation);
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
@@ -69,13 +68,13 @@ pub fn ensure_wf<'tcx>(
 }
 
 fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
-    let param_env = tcx.param_env(item_def_id);
+    let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
     let span = tcx.def_span(item_def_id.to_def_id());
-    if !ensure_wf(tcx, param_env, ty, item_def_id, span) {
+    if !ensure_wf(tcx, typing_env, ty, item_def_id, span) {
         return;
     }
-    match tcx.layout_of(param_env.and(ty)) {
+    match tcx.layout_of(typing_env.as_query_input(ty)) {
         Ok(ty_layout) => {
             // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
             // The `..` are the names of fields to dump.
@@ -107,19 +106,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
                             span,
                             homogeneous_aggregate: format!(
                                 "{:?}",
-                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
+                                ty_layout
+                                    .homogeneous_aggregate(&UnwrapLayoutCx { tcx, typing_env })
                             ),
                         });
                     }
 
                     sym::debug => {
-                        let normalized_ty = format!(
-                            "{}",
-                            tcx.normalize_erasing_regions(
-                                param_env.with_reveal_all_normalized(tcx),
-                                ty,
-                            )
-                        );
+                        let normalized_ty =
+                            format!("{}", tcx.normalize_erasing_regions(typing_env, ty));
                         // FIXME: using the `Debug` impl here isn't ideal.
                         let ty_layout = format!("{:#?}", *ty_layout);
                         tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
@@ -140,7 +135,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
 
 struct UnwrapLayoutCx<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 }
 
 impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
@@ -155,9 +150,9 @@ impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
     }
 }
 
-impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
-    fn param_env(&self) -> ParamEnv<'tcx> {
-        self.param_env
+impl<'tcx> HasTypingEnv<'tcx> for UnwrapLayoutCx<'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
     }
 }
 
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 664da65068d..8f53b71319d 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -27,7 +27,7 @@ pub mod entry;
 mod errors;
 #[cfg(debug_assertions)]
 pub mod hir_id_validator;
-pub mod hir_stats;
+pub mod input_stats;
 mod lang_items;
 pub mod layout_test;
 mod lib_features;
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 366f7dd293c..9cd95a0b02d 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -468,7 +468,7 @@ const ACC_USE: u32 = 4;
 struct Liveness<'a, 'tcx> {
     ir: &'a mut IrMaps<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     closure_min_captures: Option<&'tcx RootVariableMinCaptureList<'tcx>>,
     successors: IndexVec<LiveNode, Option<LiveNode>>,
     rwu_table: rwu_table::RWUTable,
@@ -491,7 +491,8 @@ struct Liveness<'a, 'tcx> {
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> {
         let typeck_results = ir.tcx.typeck(body_owner);
-        let param_env = ir.tcx.param_env(body_owner);
+        // FIXME(#132279): we're in a body here.
+        let typing_env = ty::TypingEnv::non_body_analysis(ir.tcx, body_owner);
         let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner);
         let closure_ln = ir.add_live_node(ClosureNode);
         let exit_ln = ir.add_live_node(ExitNode);
@@ -502,7 +503,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         Liveness {
             ir,
             typeck_results,
-            param_env,
+            typing_env,
             closure_min_captures,
             successors: IndexVec::from_elem_n(None, num_live_nodes),
             rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars),
@@ -1297,7 +1298,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode {
         let ty = self.typeck_results.expr_ty(expr);
         let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
-        if ty.is_inhabited_from(self.ir.tcx, m, self.param_env) {
+        if ty.is_inhabited_from(self.ir.tcx, m, self.typing_env) {
             return succ;
         }
         match self.ir.lnks[succ] {
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 9ea5023064c..cc0763ac751 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -9,6 +9,7 @@ use rustc_index::{Idx, IndexVec};
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::mir::{self, Const};
 use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
+use rustc_middle::traits::Reveal;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
     self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
@@ -108,6 +109,17 @@ impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> {
 }
 
 impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
+    pub fn typing_mode(&self) -> ty::TypingMode<'tcx> {
+        debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing);
+        // FIXME(#132279): This is inside of a body. If we need to use the `param_env`
+        // and `typing_mode` we should reveal opaques defined by that body.
+        ty::TypingMode::non_body_analysis()
+    }
+
+    pub fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
+    }
+
     /// Type inference occasionally gives us opaque types in places where corresponding patterns
     /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
     /// types, we use the corresponding concrete type if possible.
@@ -139,7 +151,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
         !ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
             self.tcx,
-            self.param_env,
+            self.typing_env(),
             self.module,
             &|key| self.reveal_opaque_key(key),
         )
@@ -179,7 +191,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         variant.fields.iter().map(move |field| {
             let ty = field.ty(self.tcx, args);
             // `field.ty()` doesn't normalize after instantiating.
-            let ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+            let ty = self.tcx.normalize_erasing_regions(self.typing_env(), ty);
             let ty = self.reveal_opaque_ty(ty);
             (field, ty)
         })
@@ -369,7 +381,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         let is_inhabited = v
                             .inhabited_predicate(cx.tcx, *def)
                             .instantiate(cx.tcx, args)
-                            .apply_revealing_opaque(cx.tcx, cx.param_env, cx.module, &|key| {
+                            .apply_revealing_opaque(cx.tcx, cx.typing_env(), cx.module, &|key| {
                                 cx.reveal_opaque_key(key)
                             });
                         // Variants that depend on a disabled unstable feature.
@@ -430,7 +442,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         match bdy {
             PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity,
             PatRangeBoundary::Finite(value) => {
-                let bits = value.eval_bits(self.tcx, self.param_env);
+                let bits = value.eval_bits(self.tcx, self.typing_env());
                 match *ty.kind() {
                     ty::Int(ity) => {
                         let size = Integer::from_int_ty(&self.tcx, ity).size().bits();
@@ -453,7 +465,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         let fields: Vec<_>;
         match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. }
-            | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
+            | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
@@ -539,7 +551,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             PatKind::Constant { value } => {
                 match ty.kind() {
                     ty::Bool => {
-                        ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
+                        ctor = match value.try_eval_bool(cx.tcx, cx.typing_env()) {
                             Some(b) => Bool(b),
                             None => Opaque(OpaqueId::new()),
                         };
@@ -547,7 +559,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         arity = 0;
                     }
                     ty::Char | ty::Int(_) | ty::Uint(_) => {
-                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) {
                             Some(bits) => {
                                 let x = match *ty.kind() {
                                     ty::Int(ity) => {
@@ -564,7 +576,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         arity = 0;
                     }
                     ty::Float(ty::FloatTy::F16) => {
-                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) {
                             Some(bits) => {
                                 use rustc_apfloat::Float;
                                 let value = rustc_apfloat::ieee::Half::from_bits(bits);
@@ -576,7 +588,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         arity = 0;
                     }
                     ty::Float(ty::FloatTy::F32) => {
-                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) {
                             Some(bits) => {
                                 use rustc_apfloat::Float;
                                 let value = rustc_apfloat::ieee::Single::from_bits(bits);
@@ -588,7 +600,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         arity = 0;
                     }
                     ty::Float(ty::FloatTy::F64) => {
-                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) {
                             Some(bits) => {
                                 use rustc_apfloat::Float;
                                 let value = rustc_apfloat::ieee::Double::from_bits(bits);
@@ -600,7 +612,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         arity = 0;
                     }
                     ty::Float(ty::FloatTy::F128) => {
-                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.typing_env()) {
                             Some(bits) => {
                                 use rustc_apfloat::Float;
                                 let value = rustc_apfloat::ieee::Quad::from_bits(bits);
@@ -649,8 +661,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     }
                     ty::Float(fty) => {
                         use rustc_apfloat::Float;
-                        let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env));
-                        let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env));
+                        let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env()));
+                        let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env()));
                         match fty {
                             ty::FloatTy::F16 => {
                                 use rustc_apfloat::ieee::Half;
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index ba7a631fb54..a85e8a55a21 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -2,6 +2,7 @@
 #![allow(rustc::potential_query_instability, internal_features)]
 #![feature(assert_matches)]
 #![feature(core_intrinsics)]
+#![feature(dropck_eyepatch)]
 #![feature(hash_raw_entry)]
 #![feature(let_chains)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index a4ced3d2c24..e6f3d97742d 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -3,9 +3,10 @@ use std::hash::Hash;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sharded::{self, Sharded};
-use rustc_data_structures::sync::{Lock, OnceLock};
+use rustc_data_structures::sync::OnceLock;
+pub use rustc_data_structures::vec_cache::VecCache;
 use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_index::{Idx, IndexVec};
+use rustc_index::Idx;
 use rustc_span::def_id::{DefId, DefIndex};
 
 use crate::dep_graph::DepNodeIndex;
@@ -100,52 +101,10 @@ where
     }
 }
 
-pub struct VecCache<K: Idx, V> {
-    cache: Lock<IndexVec<K, Option<(V, DepNodeIndex)>>>,
-}
-
-impl<K: Idx, V> Default for VecCache<K, V> {
-    fn default() -> Self {
-        VecCache { cache: Default::default() }
-    }
-}
-
-impl<K, V> QueryCache for VecCache<K, V>
-where
-    K: Eq + Idx + Copy + Debug,
-    V: Copy,
-{
-    type Key = K;
-    type Value = V;
-
-    #[inline(always)]
-    fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
-        let lock = self.cache.lock();
-        if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None }
-    }
-
-    #[inline]
-    fn complete(&self, key: K, value: V, index: DepNodeIndex) {
-        let mut lock = self.cache.lock();
-        lock.insert(key, (value, index));
-    }
-
-    fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
-        for (k, v) in self.cache.lock().iter_enumerated() {
-            if let Some(v) = v {
-                f(&k, &v.0, v.1);
-            }
-        }
-    }
-}
-
 pub struct DefIdCache<V> {
     /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is
     /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap.
-    ///
-    /// The second element of the tuple is the set of keys actually present in the IndexVec, used
-    /// for faster iteration in `iter()`.
-    local: Lock<(IndexVec<DefIndex, Option<(V, DepNodeIndex)>>, Vec<DefIndex>)>,
+    local: VecCache<DefIndex, V, DepNodeIndex>,
     foreign: DefaultCache<DefId, V>,
 }
 
@@ -165,8 +124,7 @@ where
     #[inline(always)]
     fn lookup(&self, key: &DefId) -> Option<(V, DepNodeIndex)> {
         if key.krate == LOCAL_CRATE {
-            let cache = self.local.lock();
-            cache.0.get(key.index).and_then(|v| *v)
+            self.local.lookup(&key.index)
         } else {
             self.foreign.lookup(key)
         }
@@ -175,27 +133,39 @@ where
     #[inline]
     fn complete(&self, key: DefId, value: V, index: DepNodeIndex) {
         if key.krate == LOCAL_CRATE {
-            let mut cache = self.local.lock();
-            let (cache, present) = &mut *cache;
-            let slot = cache.ensure_contains_elem(key.index, Default::default);
-            if slot.is_none() {
-                // FIXME: Only store the present set when running in incremental mode. `iter` is not
-                // used outside of saving caches to disk and self-profile.
-                present.push(key.index);
-            }
-            *slot = Some((value, index));
+            self.local.complete(key.index, value, index)
         } else {
             self.foreign.complete(key, value, index)
         }
     }
 
     fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
-        let guard = self.local.lock();
-        let (cache, present) = &*guard;
-        for &idx in present.iter() {
-            let value = cache[idx].unwrap();
-            f(&DefId { krate: LOCAL_CRATE, index: idx }, &value.0, value.1);
-        }
+        self.local.iter(&mut |key, value, index| {
+            f(&DefId { krate: LOCAL_CRATE, index: *key }, value, index);
+        });
         self.foreign.iter(f);
     }
 }
+
+impl<K, V> QueryCache for VecCache<K, V, DepNodeIndex>
+where
+    K: Idx + Eq + Hash + Copy + Debug,
+    V: Copy,
+{
+    type Key = K;
+    type Value = V;
+
+    #[inline(always)]
+    fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
+        self.lookup(key)
+    }
+
+    #[inline]
+    fn complete(&self, key: K, value: V, index: DepNodeIndex) {
+        self.complete(key, value, index)
+    }
+
+    fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {
+        self.iter(f)
+    }
+}
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index bdf940a04b5..293cee500bb 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1324,7 +1324,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         // This way they can use `macro_rules` defined later.
                         self.visit_vis(&item.vis);
                         self.visit_ident(&item.ident);
-                        item.kind.walk(item, AssocCtxt::Trait, self);
+                        item.kind.walk(item.span, item.id, &item.ident, &item.vis, (), self);
                         visit::walk_list!(self, visit_attribute, &item.attrs);
                     }
                     _ => visit::walk_item(self, item),
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 5437ca65935..5b78acd904a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -535,14 +535,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         filter_fn: &impl Fn(Res) -> bool,
         ctxt: Option<SyntaxContext>,
     ) {
-        for (key, resolution) in self.resolutions(module).borrow().iter() {
-            if let Some(binding) = resolution.borrow().binding {
-                let res = binding.res();
-                if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
-                    names.push(TypoSuggestion::typo_from_ident(key.ident, res));
-                }
+        module.for_each_child(self, |_this, ident, _ns, binding| {
+            let res = binding.res();
+            if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == ident.span.ctxt()) {
+                names.push(TypoSuggestion::typo_from_ident(ident, res));
             }
-        }
+        });
     }
 
     /// Combines an error with provided span and emits it.
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index b80e0e196ca..466e190028a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -38,6 +38,12 @@ impl From<UsePrelude> for bool {
     }
 }
 
+#[derive(Debug, PartialEq)]
+enum Shadowing {
+    Restricted,
+    Unrestricted,
+}
+
 impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// A generic scope visitor.
     /// Visits scopes in order to resolve some identifier in them or perform other actions.
@@ -311,13 +317,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         // Walk backwards up the ribs in scope.
         let mut module = self.graph_root;
-        for i in (0..ribs.len()).rev() {
-            debug!("walk rib\n{:?}", ribs[i].bindings);
+        for (i, rib) in ribs.iter().enumerate().rev() {
+            debug!("walk rib\n{:?}", rib.bindings);
             // Use the rib kind to determine whether we are resolving parameters
             // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
-            let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
-            if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident)
-            {
+            let rib_ident = if rib.kind.contains_params() { normalized_ident } else { ident };
+            if let Some((original_rib_ident_def, res)) = rib.bindings.get_key_value(&rib_ident) {
                 // The ident resolves to a type parameter or local variable.
                 return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
                     i,
@@ -329,7 +334,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 )));
             }
 
-            module = match ribs[i].kind {
+            module = match rib.kind {
                 RibKind::Module(module) => module,
                 RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
                     // If an invocation of this macro created `ident`, give up on `ident`
@@ -350,6 +355,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 ident,
                 ns,
                 parent_scope,
+                Shadowing::Unrestricted,
                 finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                 ignore_binding,
                 None,
@@ -494,7 +500,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     Scope::CrateRoot => {
                         let root_ident = Ident::new(kw::PathRoot, ident.span);
                         let root_module = this.resolve_crate_root(root_ident);
-                        let binding = this.resolve_ident_in_module_ext(
+                        let binding = this.resolve_ident_in_module(
                             ModuleOrUniformRoot::Module(root_module),
                             ident,
                             ns,
@@ -516,12 +522,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
                     Scope::Module(module, derive_fallback_lint_id) => {
                         let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
-                        let binding = this.resolve_ident_in_module_unadjusted_ext(
+                        let binding = this.resolve_ident_in_module_unadjusted(
                             ModuleOrUniformRoot::Module(module),
                             ident,
                             ns,
                             adjusted_parent_scope,
-                            !matches!(scope_set, ScopeSet::Late(..)),
+                            if matches!(scope_set, ScopeSet::Late(..)) {
+                                Shadowing::Unrestricted
+                            } else {
+                                Shadowing::Restricted
+                            },
                             finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                             ignore_binding,
                             ignore_import,
@@ -590,6 +600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                 ident,
                                 ns,
                                 parent_scope,
+                                Shadowing::Unrestricted,
                                 None,
                                 ignore_binding,
                                 ignore_import,
@@ -748,7 +759,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         parent_scope: &ParentScope<'ra>,
         ignore_import: Option<Import<'ra>>,
     ) -> Result<NameBinding<'ra>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import)
+        self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import)
             .map_err(|(determinacy, _)| determinacy)
     }
 
@@ -756,29 +767,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     pub(crate) fn resolve_ident_in_module(
         &mut self,
         module: ModuleOrUniformRoot<'ra>,
-        ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'ra>,
-        finalize: Option<Finalize>,
-        ignore_binding: Option<NameBinding<'ra>>,
-        ignore_import: Option<Import<'ra>>,
-    ) -> Result<NameBinding<'ra>, Determinacy> {
-        self.resolve_ident_in_module_ext(
-            module,
-            ident,
-            ns,
-            parent_scope,
-            finalize,
-            ignore_binding,
-            ignore_import,
-        )
-        .map_err(|(determinacy, _)| determinacy)
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    fn resolve_ident_in_module_ext(
-        &mut self,
-        module: ModuleOrUniformRoot<'ra>,
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'ra>,
@@ -803,52 +791,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 // No adjustments
             }
         }
-        self.resolve_ident_in_module_unadjusted_ext(
+        self.resolve_ident_in_module_unadjusted(
             module,
             ident,
             ns,
             adjusted_parent_scope,
-            false,
-            finalize,
-            ignore_binding,
-            ignore_import,
-        )
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    fn resolve_ident_in_module_unadjusted(
-        &mut self,
-        module: ModuleOrUniformRoot<'ra>,
-        ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'ra>,
-        finalize: Option<Finalize>,
-        ignore_binding: Option<NameBinding<'ra>>,
-        ignore_import: Option<Import<'ra>>,
-    ) -> Result<NameBinding<'ra>, Determinacy> {
-        self.resolve_ident_in_module_unadjusted_ext(
-            module,
-            ident,
-            ns,
-            parent_scope,
-            false,
+            Shadowing::Unrestricted,
             finalize,
             ignore_binding,
             ignore_import,
         )
-        .map_err(|(determinacy, _)| determinacy)
     }
 
     /// Attempts to resolve `ident` in namespaces `ns` of `module`.
     /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete.
     #[instrument(level = "debug", skip(self))]
-    fn resolve_ident_in_module_unadjusted_ext(
+    fn resolve_ident_in_module_unadjusted(
         &mut self,
         module: ModuleOrUniformRoot<'ra>,
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'ra>,
-        restricted_shadowing: bool,
+        shadowing: Shadowing,
         finalize: Option<Finalize>,
         // This binding should be ignored during in-module resolution, so that we don't get
         // "self-confirming" import resolutions during import validation and checking.
@@ -858,7 +822,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let module = match module {
             ModuleOrUniformRoot::Module(module) => module,
             ModuleOrUniformRoot::CrateRootAndExternPrelude => {
-                assert!(!restricted_shadowing);
+                assert_eq!(shadowing, Shadowing::Unrestricted);
                 let binding = self.early_resolve_ident_in_lexical_scope(
                     ident,
                     ScopeSet::AbsolutePath(ns),
@@ -871,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
             ModuleOrUniformRoot::ExternPrelude => {
-                assert!(!restricted_shadowing);
+                assert_eq!(shadowing, Shadowing::Unrestricted);
                 return if ns != TypeNS {
                     Err((Determined, Weak::No))
                 } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) {
@@ -884,7 +848,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 };
             }
             ModuleOrUniformRoot::CurrentScope => {
-                assert!(!restricted_shadowing);
+                assert_eq!(shadowing, Shadowing::Unrestricted);
                 if ns == TypeNS {
                     if ident.name == kw::Crate || ident.name == kw::DollarCrate {
                         let module = self.resolve_crate_root(ident);
@@ -943,7 +907,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
             // Forbid expanded shadowing to avoid time travel.
             if let Some(shadowed_glob) = resolution.shadowed_glob
-                && restricted_shadowing
+                && shadowing == Shadowing::Restricted
                 && binding.expansion != LocalExpnId::ROOT
                 && binding.res() != shadowed_glob.res()
             {
@@ -958,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 });
             }
 
-            if !restricted_shadowing
+            if shadowing == Shadowing::Unrestricted
                 && binding.expansion != LocalExpnId::ROOT
                 && let NameBindingKind::Import { import, .. } = binding.kind
                 && matches!(import.kind, ImportKind::MacroExport)
@@ -1047,13 +1011,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 ignore_binding,
                 ignore_import,
             ) {
-                Err(Determined) => continue,
+                Err((Determined, _)) => continue,
                 Ok(binding)
                     if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) =>
                 {
                     continue;
                 }
-                Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)),
+                Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::No)),
             }
         }
 
@@ -1070,7 +1034,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
         // shadowing is enabled, see `macro_expanded_macro_export_errors`).
         if let Some(binding) = binding {
-            if binding.determined() || ns == MacroNS || restricted_shadowing {
+            if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted {
                 return check_usable(self, binding);
             } else {
                 return Err((Undetermined, Weak::No));
@@ -1122,19 +1086,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 ident,
                 ns,
                 adjusted_parent_scope,
+                Shadowing::Unrestricted,
                 None,
                 ignore_binding,
                 ignore_import,
             );
 
             match result {
-                Err(Determined) => continue,
+                Err((Determined, _)) => continue,
                 Ok(binding)
                     if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) =>
                 {
                     continue;
                 }
-                Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)),
+                Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::Yes)),
             }
         }
 
@@ -1200,7 +1165,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             // Still doesn't deal with upvars
                             if let Some(span) = finalize {
                                 let (span, resolution_error) = match item {
-                                    None if rib_ident.as_str() == "self" => (span, LowercaseSelf),
+                                    None if rib_ident.name == kw::SelfLower => {
+                                        (span, LowercaseSelf)
+                                    }
                                     None => {
                                         // If we have a `let name = expr;`, we have the span for
                                         // `name` and use that to see if it is followed by a type
@@ -1511,9 +1478,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 if segment_idx == 0 {
                     if name == kw::SelfLower {
                         let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
-                        module = Some(ModuleOrUniformRoot::Module(
-                            self.resolve_self(&mut ctxt, parent_scope.module),
-                        ));
+                        let self_mod = self.resolve_self(&mut ctxt, parent_scope.module);
+                        if let Some(res) = self_mod.res() {
+                            record_segment_res(self, res);
+                        }
+                        module = Some(ModuleOrUniformRoot::Module(self_mod));
                         continue;
                     }
                     if name == kw::PathRoot && ident.span.at_least_rust_2018() {
@@ -1530,7 +1499,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
                     if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate {
                         // `::a::b`, `crate::a::b` or `$crate::a::b`
-                        module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident)));
+                        let crate_root = self.resolve_crate_root(ident);
+                        if let Some(res) = crate_root.res() {
+                            record_segment_res(self, res);
+                        }
+                        module = Some(ModuleOrUniformRoot::Module(crate_root));
                         continue;
                     }
                 }
@@ -1563,6 +1536,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     ignore_binding,
                     ignore_import,
                 )
+                .map_err(|(determinacy, _)| determinacy)
             } else if let Some(ribs) = ribs
                 && let Some(TypeNS | ValueNS) = opt_ns
             {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index f4a85c358e3..26b345f5941 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1688,9 +1688,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             }
         }
 
+        let normalized_ident = ident.normalize_to_macros_2_0();
         let mut outer_res = None;
         for rib in lifetime_rib_iter {
-            let normalized_ident = ident.normalize_to_macros_2_0();
             if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
                 outer_res = Some(outer);
                 break;
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9abb3180388..e382295b8f6 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1082,8 +1082,6 @@ pub struct Resolver<'ra, 'tcx> {
     binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>,
 
     underscore_disambiguator: u32,
-    /// Disambiguator for anonymous adts.
-    empty_disambiguator: u32,
 
     /// Maps glob imports to the names of items actually imported.
     glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
@@ -1462,7 +1460,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             module_children: Default::default(),
             trait_map: NodeMap::default(),
             underscore_disambiguator: 0,
-            empty_disambiguator: 0,
             empty_module,
             module_map,
             block_map: Default::default(),
@@ -1809,12 +1806,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         assoc_item: Option<(Symbol, Namespace)>,
     ) -> bool {
         match (trait_module, assoc_item) {
-            (Some(trait_module), Some((name, ns))) => {
-                self.resolutions(trait_module).borrow().iter().any(|resolution| {
-                    let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution;
-                    assoc_ns == ns && assoc_ident.name == name
-                })
-            }
+            (Some(trait_module), Some((name, ns))) => self
+                .resolutions(trait_module)
+                .borrow()
+                .iter()
+                .any(|(key, _name_resolution)| key.ns == ns && key.ident.name == name),
             _ => true,
         }
     }
@@ -1842,9 +1838,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let disambiguator = if ident.name == kw::Underscore {
             self.underscore_disambiguator += 1;
             self.underscore_disambiguator
-        } else if ident.name == kw::Empty {
-            self.empty_disambiguator += 1;
-            self.empty_disambiguator
         } else {
             0
         };
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 0e6f905e7a1..2f4387e412d 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -133,7 +133,7 @@ fn encode_const<'tcx>(
             match ct_ty.kind() {
                 ty::Int(ity) => {
                     let bits = c
-                        .try_to_bits(tcx, ty::ParamEnv::reveal_all())
+                        .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in cfi");
                     let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
                     if val < 0 {
@@ -143,7 +143,7 @@ fn encode_const<'tcx>(
                 }
                 ty::Uint(_) => {
                     let val = c
-                        .try_to_bits(tcx, ty::ParamEnv::reveal_all())
+                        .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in cfi");
                     let _ = write!(s, "{val}");
                 }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
index 01568a0f61c..562e288afaa 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
@@ -117,7 +117,9 @@ pub fn typeid_for_instance<'tcx>(
         .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
     let instance = transform_instance(tcx, instance, transform_ty_options);
     let fn_abi = tcx
-        .fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty())))
+        .fn_abi_of_instance(
+            ty::TypingEnv::fully_monomorphized().as_query_input((instance, ty::List::empty())),
+        )
         .unwrap_or_else(|error| {
             bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
         });
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index cba79a02f8b..9c01bd04353 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -136,18 +136,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
                         return t;
                     }
                     let variant = adt_def.non_enum_variant();
-                    let param_env = self.tcx.param_env(variant.def_id);
+                    let typing_env = ty::TypingEnv::post_analysis(self.tcx, variant.def_id);
                     let field = variant.fields.iter().find(|field| {
                         let ty = self.tcx.type_of(field.did).instantiate_identity();
                         let is_zst = self
                             .tcx
-                            .layout_of(param_env.and(ty))
+                            .layout_of(typing_env.as_query_input(ty))
                             .is_ok_and(|layout| layout.is_zst());
                         !is_zst
                     });
                     if let Some(field) = field {
                         let ty0 = self.tcx.normalize_erasing_regions(
-                            ty::ParamEnv::reveal_all(),
+                            ty::TypingEnv::fully_monomorphized(),
                             field.ty(self.tcx, args),
                         );
                         // Generalize any repr(transparent) user-defined type that is either a
@@ -209,9 +209,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
                 }
             }
 
-            ty::Alias(..) => {
-                self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
-            }
+            ty::Alias(..) => self.fold_ty(
+                self.tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), t),
+            ),
 
             ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
                 bug!("fold_ty: unexpected `{:?}`", t.kind());
@@ -241,7 +241,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
                         let alias_ty =
                             ty::AliasTy::new_from_args(tcx, assoc_ty.def_id, super_trait_ref.args);
                         let resolved = tcx.normalize_erasing_regions(
-                            ty::ParamEnv::reveal_all(),
+                            ty::TypingEnv::fully_monomorphized(),
                             alias_ty.to_ty(tcx),
                         );
                         debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
@@ -376,7 +376,7 @@ pub(crate) fn transform_instance<'tcx>(
             // implementation will not. We need to walk back to the more general trait method
             let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
                 instance.args,
-                ty::ParamEnv::reveal_all(),
+                ty::TypingEnv::fully_monomorphized(),
                 trait_ref,
             );
             let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
@@ -397,7 +397,7 @@ pub(crate) fn transform_instance<'tcx>(
         } else if tcx.is_closure_like(instance.def_id()) {
             // We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
             // instantiate it, and take the type of its only method as our own.
-            let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+            let closure_ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized());
             let (trait_id, inputs) = match closure_ty.kind() {
                 ty::Closure(..) => {
                     let closure_args = instance.args.as_closure();
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 44721bd889a..d60c56fee75 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -30,17 +30,18 @@ use rustc_target::spec::{
 };
 use tracing::debug;
 
+pub use crate::config::cfg::{Cfg, CheckCfg, ExpectedValues};
+use crate::config::native_libs::parse_native_libs;
 use crate::errors::FileWriteFail;
 pub use crate::options::*;
 use crate::search_paths::SearchPath;
-use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
+use crate::utils::CanonicalizedPath;
 use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};
 
 mod cfg;
+mod native_libs;
 pub mod sigpipe;
 
-pub use cfg::{Cfg, CheckCfg, ExpectedValues};
-
 /// The different settings that the `-C strip` flag can have.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum Strip {
@@ -1068,7 +1069,7 @@ impl OutputFilenames {
         self.with_directory_and_extension(&self.out_directory, extension)
     }
 
-    fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
+    pub fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
         let mut path = directory.join(&self.filestem);
         path.set_extension(extension);
         path
@@ -2134,143 +2135,6 @@ fn parse_assert_incr_state(
     }
 }
 
-fn parse_native_lib_kind(
-    early_dcx: &EarlyDiagCtxt,
-    matches: &getopts::Matches,
-    kind: &str,
-) -> (NativeLibKind, Option<bool>) {
-    let (kind, modifiers) = match kind.split_once(':') {
-        None => (kind, None),
-        Some((kind, modifiers)) => (kind, Some(modifiers)),
-    };
-
-    let kind = match kind {
-        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
-        "dylib" => NativeLibKind::Dylib { as_needed: None },
-        "framework" => NativeLibKind::Framework { as_needed: None },
-        "link-arg" => {
-            if !nightly_options::is_unstable_enabled(matches) {
-                let why = if nightly_options::match_is_nightly_build(matches) {
-                    " and only accepted on the nightly compiler"
-                } else {
-                    ", the `-Z unstable-options` flag must also be passed to use it"
-                };
-                early_dcx.early_fatal(format!("library kind `link-arg` is unstable{why}"))
-            }
-            NativeLibKind::LinkArg
-        }
-        _ => early_dcx.early_fatal(format!(
-            "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
-        )),
-    };
-    match modifiers {
-        None => (kind, None),
-        Some(modifiers) => parse_native_lib_modifiers(early_dcx, kind, modifiers, matches),
-    }
-}
-
-fn parse_native_lib_modifiers(
-    early_dcx: &EarlyDiagCtxt,
-    mut kind: NativeLibKind,
-    modifiers: &str,
-    matches: &getopts::Matches,
-) -> (NativeLibKind, Option<bool>) {
-    let mut verbatim = None;
-    for modifier in modifiers.split(',') {
-        let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
-            Some(m) => (m, modifier.starts_with('+')),
-            None => early_dcx.early_fatal(
-                "invalid linking modifier syntax, expected '+' or '-' prefix \
-                 before one of: bundle, verbatim, whole-archive, as-needed",
-            ),
-        };
-
-        let report_unstable_modifier = || {
-            if !nightly_options::is_unstable_enabled(matches) {
-                let why = if nightly_options::match_is_nightly_build(matches) {
-                    " and only accepted on the nightly compiler"
-                } else {
-                    ", the `-Z unstable-options` flag must also be passed to use it"
-                };
-                early_dcx.early_fatal(format!("linking modifier `{modifier}` is unstable{why}"))
-            }
-        };
-        let assign_modifier = |dst: &mut Option<bool>| {
-            if dst.is_some() {
-                let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
-                early_dcx.early_fatal(msg)
-            } else {
-                *dst = Some(value);
-            }
-        };
-        match (modifier, &mut kind) {
-            ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
-            ("bundle", _) => early_dcx.early_fatal(
-                "linking modifier `bundle` is only compatible with `static` linking kind",
-            ),
-
-            ("verbatim", _) => assign_modifier(&mut verbatim),
-
-            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
-                assign_modifier(whole_archive)
-            }
-            ("whole-archive", _) => early_dcx.early_fatal(
-                "linking modifier `whole-archive` is only compatible with `static` linking kind",
-            ),
-
-            ("as-needed", NativeLibKind::Dylib { as_needed })
-            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
-                report_unstable_modifier();
-                assign_modifier(as_needed)
-            }
-            ("as-needed", _) => early_dcx.early_fatal(
-                "linking modifier `as-needed` is only compatible with \
-                 `dylib` and `framework` linking kinds",
-            ),
-
-            // Note: this error also excludes the case with empty modifier
-            // string, like `modifiers = ""`.
-            _ => early_dcx.early_fatal(format!(
-                "unknown linking modifier `{modifier}`, expected one \
-                     of: bundle, verbatim, whole-archive, as-needed"
-            )),
-        }
-    }
-
-    (kind, verbatim)
-}
-
-fn parse_libs(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Vec<NativeLib> {
-    matches
-        .opt_strs("l")
-        .into_iter()
-        .map(|s| {
-            // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
-            // where KIND is one of "dylib", "framework", "static", "link-arg" and
-            // where MODIFIERS are a comma separated list of supported modifiers
-            // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
-            // with either + or - to indicate whether it is enabled or disabled.
-            // The last value specified for a given modifier wins.
-            let (name, kind, verbatim) = match s.split_once('=') {
-                None => (s, NativeLibKind::Unspecified, None),
-                Some((kind, name)) => {
-                    let (kind, verbatim) = parse_native_lib_kind(early_dcx, matches, kind);
-                    (name.to_string(), kind, verbatim)
-                }
-            };
-
-            let (name, new_name) = match name.split_once(':') {
-                None => (name, None),
-                Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
-            };
-            if name.is_empty() {
-                early_dcx.early_fatal("library name must not be empty");
-            }
-            NativeLib { name, new_name, kind, verbatim }
-        })
-        .collect()
-}
-
 pub fn parse_externs(
     early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
@@ -2644,7 +2508,10 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
     let debuginfo = select_debuginfo(matches, &cg);
     let debuginfo_compression = unstable_opts.debuginfo_compression;
 
-    let libs = parse_libs(early_dcx, matches);
+    let crate_name = matches.opt_str("crate-name");
+    let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
+    // Parse any `-l` flags, which link to native libraries.
+    let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches);
 
     let test = matches.opt_present("test");
 
@@ -2659,8 +2526,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let externs = parse_externs(early_dcx, matches, &unstable_opts);
 
-    let crate_name = matches.opt_str("crate-name");
-
     let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
 
     let pretty = parse_pretty(early_dcx, &unstable_opts);
@@ -2734,7 +2599,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         error_format,
         diagnostic_width,
         externs,
-        unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
+        unstable_features,
         crate_name,
         libs,
         debug_assertions,
diff --git a/compiler/rustc_session/src/config/native_libs.rs b/compiler/rustc_session/src/config/native_libs.rs
new file mode 100644
index 00000000000..f1f0aeb5e59
--- /dev/null
+++ b/compiler/rustc_session/src/config/native_libs.rs
@@ -0,0 +1,192 @@
+//! Parser for the `-l` command-line option, which links the generated crate to
+//! a native library.
+//!
+//! (There is also a similar but separate syntax for `#[link]` attributes,
+//! which have their own parser in `rustc_metadata`.)
+
+use rustc_feature::UnstableFeatures;
+
+use crate::EarlyDiagCtxt;
+use crate::config::UnstableOptions;
+use crate::utils::{NativeLib, NativeLibKind};
+
+#[cfg(test)]
+mod tests;
+
+/// Parses all `-l` options.
+pub(crate) fn parse_native_libs(
+    early_dcx: &EarlyDiagCtxt,
+    unstable_opts: &UnstableOptions,
+    unstable_features: UnstableFeatures,
+    matches: &getopts::Matches,
+) -> Vec<NativeLib> {
+    let cx = ParseNativeLibCx {
+        early_dcx,
+        unstable_options_enabled: unstable_opts.unstable_options,
+        is_nightly: unstable_features.is_nightly_build(),
+    };
+    matches.opt_strs("l").into_iter().map(|value| parse_native_lib(&cx, &value)).collect()
+}
+
+struct ParseNativeLibCx<'a> {
+    early_dcx: &'a EarlyDiagCtxt,
+    unstable_options_enabled: bool,
+    is_nightly: bool,
+}
+
+impl ParseNativeLibCx<'_> {
+    /// If unstable values are not permitted, exits with a fatal error made by
+    /// combining the given strings.
+    fn on_unstable_value(&self, message: &str, if_nightly: &str, if_stable: &str) {
+        if self.unstable_options_enabled {
+            return;
+        }
+
+        let suffix = if self.is_nightly { if_nightly } else { if_stable };
+        self.early_dcx.early_fatal(format!("{message}{suffix}"));
+    }
+}
+
+/// Parses the value of a single `-l` option.
+fn parse_native_lib(cx: &ParseNativeLibCx<'_>, value: &str) -> NativeLib {
+    let NativeLibParts { kind, modifiers, name, new_name } = split_native_lib_value(value);
+
+    let kind = kind.map_or(NativeLibKind::Unspecified, |kind| match kind {
+        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+        "dylib" => NativeLibKind::Dylib { as_needed: None },
+        "framework" => NativeLibKind::Framework { as_needed: None },
+        "link-arg" => {
+            cx.on_unstable_value(
+                "library kind `link-arg` is unstable",
+                ", the `-Z unstable-options` flag must also be passed to use it",
+                " and only accepted on the nightly compiler",
+            );
+            NativeLibKind::LinkArg
+        }
+        _ => cx.early_dcx.early_fatal(format!(
+            "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
+        )),
+    });
+
+    // Provisionally create the result, so that modifiers can modify it.
+    let mut native_lib = NativeLib {
+        name: name.to_owned(),
+        new_name: new_name.map(str::to_owned),
+        kind,
+        verbatim: None,
+    };
+
+    if let Some(modifiers) = modifiers {
+        // If multiple modifiers are present, they are separated by commas.
+        for modifier in modifiers.split(',') {
+            parse_and_apply_modifier(cx, modifier, &mut native_lib);
+        }
+    }
+
+    if native_lib.name.is_empty() {
+        cx.early_dcx.early_fatal("library name must not be empty");
+    }
+
+    native_lib
+}
+
+/// Parses one of the comma-separated modifiers (prefixed by `+` or `-`), and
+/// modifies `native_lib` appropriately.
+///
+/// Exits with a fatal error if a malformed/unknown/inappropriate modifier is
+/// found.
+fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_lib: &mut NativeLib) {
+    let early_dcx = cx.early_dcx;
+
+    // Split off the leading `+` or `-` into a boolean value.
+    let (modifier, value) = match modifier.split_at_checked(1) {
+        Some(("+", m)) => (m, true),
+        Some(("-", m)) => (m, false),
+        _ => cx.early_dcx.early_fatal(
+            "invalid linking modifier syntax, expected '+' or '-' prefix \
+             before one of: bundle, verbatim, whole-archive, as-needed",
+        ),
+    };
+
+    // Assigns the value (from `+` or `-`) to an empty `Option<bool>`, or emits
+    // a fatal error if the option has already been set.
+    let assign_modifier = |opt_bool: &mut Option<bool>| {
+        if opt_bool.is_some() {
+            let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
+            early_dcx.early_fatal(msg)
+        }
+        *opt_bool = Some(value);
+    };
+
+    // Check that the modifier is applicable to the native lib kind, and apply it.
+    match (modifier, &mut native_lib.kind) {
+        ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
+        ("bundle", _) => early_dcx
+            .early_fatal("linking modifier `bundle` is only compatible with `static` linking kind"),
+
+        ("verbatim", _) => assign_modifier(&mut native_lib.verbatim),
+
+        ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+            assign_modifier(whole_archive)
+        }
+        ("whole-archive", _) => early_dcx.early_fatal(
+            "linking modifier `whole-archive` is only compatible with `static` linking kind",
+        ),
+
+        ("as-needed", NativeLibKind::Dylib { as_needed })
+        | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+            cx.on_unstable_value(
+                "linking modifier `as-needed` is unstable",
+                ", the `-Z unstable-options` flag must also be passed to use it",
+                " and only accepted on the nightly compiler",
+            );
+            assign_modifier(as_needed)
+        }
+        ("as-needed", _) => early_dcx.early_fatal(
+            "linking modifier `as-needed` is only compatible with \
+             `dylib` and `framework` linking kinds",
+        ),
+
+        _ => early_dcx.early_fatal(format!(
+            "unknown linking modifier `{modifier}`, expected one \
+             of: bundle, verbatim, whole-archive, as-needed"
+        )),
+    }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+struct NativeLibParts<'a> {
+    kind: Option<&'a str>,
+    modifiers: Option<&'a str>,
+    name: &'a str,
+    new_name: Option<&'a str>,
+}
+
+/// Splits a string of the form `[KIND[:MODIFIERS]=]NAME[:NEW_NAME]` into those
+/// individual parts. This cannot fail, but the resulting strings require
+/// further validation.
+fn split_native_lib_value(value: &str) -> NativeLibParts<'_> {
+    // Split the initial value into `[KIND=]NAME`.
+    let name = value;
+    let (kind, name) = match name.split_once('=') {
+        Some((prefix, name)) => (Some(prefix), name),
+        None => (None, name),
+    };
+
+    // Split the kind part, if present, into `KIND[:MODIFIERS]`.
+    let (kind, modifiers) = match kind {
+        Some(kind) => match kind.split_once(':') {
+            Some((kind, modifiers)) => (Some(kind), Some(modifiers)),
+            None => (Some(kind), None),
+        },
+        None => (None, None),
+    };
+
+    // Split the name part into `NAME[:NEW_NAME]`.
+    let (name, new_name) = match name.split_once(':') {
+        Some((name, new_name)) => (name, Some(new_name)),
+        None => (name, None),
+    };
+
+    NativeLibParts { kind, modifiers, name, new_name }
+}
diff --git a/compiler/rustc_session/src/config/native_libs/tests.rs b/compiler/rustc_session/src/config/native_libs/tests.rs
new file mode 100644
index 00000000000..3bcab93ef4b
--- /dev/null
+++ b/compiler/rustc_session/src/config/native_libs/tests.rs
@@ -0,0 +1,50 @@
+use crate::config::native_libs::{NativeLibParts, split_native_lib_value};
+
+#[test]
+fn split() {
+    // This is a unit test for some implementation details, so consider deleting
+    // it if it gets in the way.
+    use NativeLibParts as P;
+
+    let examples = &[
+        ("", P { kind: None, modifiers: None, name: "", new_name: None }),
+        ("foo", P { kind: None, modifiers: None, name: "foo", new_name: None }),
+        ("foo:", P { kind: None, modifiers: None, name: "foo", new_name: Some("") }),
+        ("foo:bar", P { kind: None, modifiers: None, name: "foo", new_name: Some("bar") }),
+        (":bar", P { kind: None, modifiers: None, name: "", new_name: Some("bar") }),
+        ("kind=foo", P { kind: Some("kind"), modifiers: None, name: "foo", new_name: None }),
+        (":mods=foo", P { kind: Some(""), modifiers: Some("mods"), name: "foo", new_name: None }),
+        (":mods=:bar", P {
+            kind: Some(""),
+            modifiers: Some("mods"),
+            name: "",
+            new_name: Some("bar"),
+        }),
+        ("kind=foo:bar", P {
+            kind: Some("kind"),
+            modifiers: None,
+            name: "foo",
+            new_name: Some("bar"),
+        }),
+        ("kind:mods=foo", P {
+            kind: Some("kind"),
+            modifiers: Some("mods"),
+            name: "foo",
+            new_name: None,
+        }),
+        ("kind:mods=foo:bar", P {
+            kind: Some("kind"),
+            modifiers: Some("mods"),
+            name: "foo",
+            new_name: Some("bar"),
+        }),
+        ("::==::", P { kind: Some(""), modifiers: Some(":"), name: "=", new_name: Some(":") }),
+        ("==::==", P { kind: Some(""), modifiers: None, name: "=", new_name: Some(":==") }),
+    ];
+
+    for &(value, ref expected) in examples {
+        println!("{value:?}");
+        let actual = split_native_lib_value(value);
+        assert_eq!(&actual, expected);
+    }
+}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f485e8cace5..cbfe5d22f1d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1805,8 +1805,6 @@ 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"),
-    hir_stats: bool = (false, parse_bool, [UNTRACKED],
-        "print some statistics about AST and HIR (default: no)"),
     human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
         "generate human-readable, predictable names for codegen units (default: no)"),
     identify_regions: bool = (false, parse_bool, [UNTRACKED],
@@ -1838,7 +1836,7 @@ options! {
     inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
         "a default MIR inlining threshold (default: 50)"),
     input_stats: bool = (false, parse_bool, [UNTRACKED],
-        "gather statistics about the input (default: no)"),
+        "print some statistics about AST and HIR (default: no)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],
@@ -1889,7 +1887,7 @@ options! {
     meta_stats: bool = (false, parse_bool, [UNTRACKED],
         "gather metadata statistics (default: no)"),
     metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
-        "stores metrics about the errors being emitted by rustc to disk"),
+        "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 5c09879f60e..4e8db6096d4 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -41,7 +41,7 @@ pub(crate) fn try_new_allocation<'tcx>(
             let size = scalar.size();
             let align = tables
                 .tcx
-                .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
+                .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?
                 .align;
             let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
@@ -53,7 +53,7 @@ pub(crate) fn try_new_allocation<'tcx>(
         ConstValue::ZeroSized => {
             let align = tables
                 .tcx
-                .layout_of(rustc_middle::ty::ParamEnv::empty().and(ty))
+                .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?
                 .align;
             new_empty_allocation(align.abi)
@@ -66,7 +66,7 @@ pub(crate) fn try_new_allocation<'tcx>(
                 rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
             let layout = tables
                 .tcx
-                .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
+                .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?;
             let mut allocation =
                 rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
@@ -90,7 +90,7 @@ pub(crate) fn try_new_allocation<'tcx>(
             let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory();
             let ty_size = tables
                 .tcx
-                .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
+                .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?
                 .size;
             allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables)
diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs
index cd91fc26c10..2eb0cea0e85 100644
--- a/compiler/rustc_smir/src/rustc_smir/builder.rs
+++ b/compiler/rustc_smir/src/rustc_smir/builder.rs
@@ -40,7 +40,7 @@ impl<'tcx> BodyBuilder<'tcx> {
         {
             let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions(
                 tables.tcx,
-                ty::ParamEnv::reveal_all(),
+                ty::TypingEnv::fully_monomorphized(),
                 ty::EarlyBinder::bind(body),
             );
             self.visit_body(&mut mono_body);
@@ -60,7 +60,7 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
         location: mir::Location,
     ) {
         let const_ = constant.const_;
-        let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), constant.span) {
+        let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) {
             Ok(v) => v,
             Err(mir::interpret::ErrorHandled::Reported(..)) => return,
             Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 3db65692af7..9025b47c422 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -11,11 +11,11 @@ use std::iter;
 use rustc_abi::HasDataLayout;
 use rustc_hir::LangItem;
 use rustc_middle::ty::layout::{
-    FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers,
+    FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers,
 };
 use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
+    GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
 };
 use rustc_middle::{mir, ty};
 use rustc_span::def_id::LOCAL_CRATE;
@@ -410,7 +410,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let mir_const = cnst.internal(&mut *tables, tcx);
         mir_const
-            .try_eval_target_usize(tables.tcx, ParamEnv::empty())
+            .try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized())
             .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
     }
     fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
@@ -428,7 +428,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let ty_internal = ty.internal(&mut *tables, tcx);
         let size = tables
             .tcx
-            .layout_of(ParamEnv::empty().and(ty_internal))
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty_internal))
             .map_err(|err| {
                 Error::new(format!(
                     "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
@@ -469,7 +469,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let mut tables = self.0.borrow_mut();
         let tcx = tables.tcx;
         let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
-        let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
+        let size = tables
+            .tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
+            .unwrap()
+            .size;
 
         // We don't use Const::from_bits since it doesn't have any error checking.
         let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
@@ -486,7 +490,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let mut tables = self.0.borrow_mut();
         let tcx = tables.tcx;
         let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
-        let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
+        let size = tables
+            .tcx
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
+            .unwrap()
+            .size;
 
         // We don't use Const::from_bits since it doesn't have any error checking.
         let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
@@ -523,7 +531,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let def_ty = tables.tcx.type_of(item.internal(&mut *tables, tcx));
         tables
             .tcx
-            .instantiate_and_normalize_erasing_regions(args, ty::ParamEnv::reveal_all(), def_ty)
+            .instantiate_and_normalize_erasing_regions(
+                args,
+                ty::TypingEnv::fully_monomorphized(),
+                def_ty,
+            )
             .stable(&mut *tables)
     }
 
@@ -573,7 +585,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let mut tables = self.0.borrow_mut();
         let instance = tables.instances[def];
         assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
-        instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables)
+        instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables)
     }
 
     fn instance_args(&self, def: InstanceDef) -> GenericArgs {
@@ -642,7 +654,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let def_id = def.0.internal(&mut *tables, tcx);
         let args_ref = args.internal(&mut *tables, tcx);
-        match Instance::try_resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
+        match Instance::try_resolve(
+            tables.tcx,
+            ty::TypingEnv::fully_monomorphized(),
+            def_id,
+            args_ref,
+        ) {
             Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
             Ok(None) | Err(_) => None,
         }
@@ -665,8 +682,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let def_id = def.0.internal(&mut *tables, tcx);
         let args_ref = args.internal(&mut *tables, tcx);
-        Instance::resolve_for_fn_ptr(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref)
-            .stable(&mut *tables)
+        Instance::resolve_for_fn_ptr(
+            tables.tcx,
+            ty::TypingEnv::fully_monomorphized(),
+            def_id,
+            args_ref,
+        )
+        .stable(&mut *tables)
     }
 
     fn resolve_closure(
@@ -691,7 +713,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let instance = tables.instances[def];
         let tcx = tables.tcx;
         let result = tcx.const_eval_instance(
-            ParamEnv::reveal_all(),
+            ty::TypingEnv::fully_monomorphized(),
             instance,
             tcx.def_span(instance.def_id()),
         );
@@ -827,9 +849,9 @@ impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
     }
 }
 
-impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        ty::ParamEnv::reveal_all()
+impl<'tcx> HasTypingEnv<'tcx> for Tables<'tcx> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
     }
 }
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 820d8a6be25..fcdf8703b14 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -151,6 +151,10 @@ impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
             mir::StatementKind::ConstEvalCounter => {
                 stable_mir::mir::StatementKind::ConstEvalCounter
             }
+            // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop.
+            mir::StatementKind::BackwardIncompatibleDropHint { .. } => {
+                stable_mir::mir::StatementKind::Nop
+            }
             mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop,
         }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 42c6221dc57..a2d9859645f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -316,6 +316,7 @@ symbols! {
         SubdiagMessage,
         Subdiagnostic,
         Sync,
+        SyncUnsafeCell,
         T,
         Target,
         ToOwned,
@@ -409,7 +410,6 @@ symbols! {
         arm,
         arm_target_feature,
         array,
-        as_mut_ptr,
         as_ptr,
         as_ref,
         as_str,
@@ -589,6 +589,7 @@ symbols! {
         cmse_nonsecure_entry,
         coerce_unsized,
         cold,
+        cold_path,
         collapse_debuginfo,
         column,
         compare_bytes,
@@ -1225,6 +1226,7 @@ symbols! {
         min_const_generics,
         min_const_unsafe_fn,
         min_exhaustive_patterns,
+        min_generic_const_args,
         min_specialization,
         min_type_alias_impl_trait,
         minnumf128,
@@ -1653,6 +1655,7 @@ symbols! {
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
         rustc_allowed_through_unstable_modules,
+        rustc_as_ptr,
         rustc_attrs,
         rustc_autodiff,
         rustc_box,
@@ -1665,7 +1668,6 @@ symbols! {
         rustc_const_panic_str,
         rustc_const_stable,
         rustc_const_stable_indirect,
-        rustc_const_stable_intrinsic,
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_deallocator,
@@ -1695,6 +1697,7 @@ symbols! {
         rustc_inherit_overflow_checks,
         rustc_insignificant_dtor,
         rustc_intrinsic,
+        rustc_intrinsic_const_stable_indirect,
         rustc_intrinsic_must_be_overridden,
         rustc_layout,
         rustc_layout_scalar_valid_range_end,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 05b4ff327a9..dcbc5f0f76d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -26,7 +26,7 @@ pub(super) fn mangle<'tcx>(
 ) -> String {
     let def_id = instance.def_id();
     // FIXME(eddyb) this should ideally not be needed.
-    let args = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.args);
+    let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args);
 
     let prefix = "_R";
     let mut cx: SymbolMangler<'_> = SymbolMangler {
@@ -233,19 +233,20 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         let key = self.tcx.def_key(impl_def_id);
         let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
 
-        let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
+        let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
         if !args.is_empty() {
-            param_env = EarlyBinder::bind(param_env).instantiate(self.tcx, args);
+            typing_env.param_env =
+                EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
         }
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
                 assert_eq!(impl_trait_ref.self_ty(), self_ty);
-                *impl_trait_ref = self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref);
+                *impl_trait_ref = self.tcx.normalize_erasing_regions(typing_env, *impl_trait_ref);
                 self_ty = impl_trait_ref.self_ty();
             }
             None => {
-                self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty);
+                self_ty = self.tcx.normalize_erasing_regions(typing_env, self_ty);
             }
         }
 
@@ -591,7 +592,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 ct_ty.print(self)?;
 
                 let mut bits = ct
-                    .try_to_bits(self.tcx, ty::ParamEnv::reveal_all())
+                    .try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized())
                     .expect("expected const to be monomorphic");
 
                 // Negative integer values are mangled using `n` as a "sign prefix".
diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs
index 502e7331267..c99eb9226ef 100644
--- a/compiler/rustc_target/src/callconv/s390x.rs
+++ b/compiler/rustc_target/src/callconv/s390x.rs
@@ -1,12 +1,16 @@
-// FIXME: The assumes we're using the non-vector ABI, i.e., compiling
-// for a pre-z13 machine or using -mno-vx.
+// Reference: ELF Application Binary Interface s390x Supplement
+// https://github.com/IBM/s390x-abi
 
-use crate::abi::call::{ArgAbi, FnAbi, Reg};
-use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind};
+use crate::abi::{BackendRepr, HasDataLayout, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
-    if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
+    let size = ret.layout.size;
+    if size.bits() <= 128 && matches!(ret.layout.backend_repr, BackendRepr::Vector { .. }) {
+        return;
+    }
+    if !ret.layout.is_aggregate() && size.bits() <= 64 {
         ret.extend_integer_width_to(64);
     } else {
         ret.make_indirect();
@@ -32,19 +36,25 @@ where
         }
         return;
     }
-    if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
+
+    let size = arg.layout.size;
+    if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) {
+        arg.cast_to(Reg { kind: RegKind::Vector, size });
+        return;
+    }
+    if !arg.layout.is_aggregate() && size.bits() <= 64 {
         arg.extend_integer_width_to(64);
         return;
     }
 
     if arg.layout.is_single_fp_element(cx) {
-        match arg.layout.size.bytes() {
+        match size.bytes() {
             4 => arg.cast_to(Reg::f32()),
             8 => arg.cast_to(Reg::f64()),
             _ => arg.make_indirect(),
         }
     } else {
-        match arg.layout.size.bytes() {
+        match size.bytes() {
             1 => arg.cast_to(Reg::i8()),
             2 => arg.cast_to(Reg::i16()),
             4 => arg.cast_to(Reg::i32()),
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
index 3efbb464836..a84a18a433f 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
@@ -6,9 +6,6 @@ pub(crate) fn target() -> Target {
     base.endian = Endian::Big;
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".into();
-    // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector
-    // ABI. Pass the -vector feature string to LLVM to respect this assumption.
-    base.features = "-vector".into();
     base.max_atomic_width = Some(128);
     base.min_global_align = Some(16);
     base.stack_probes = StackProbeType::Inline;
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
index 65b5c1167bd..4bde0fb729c 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
@@ -6,9 +6,6 @@ pub(crate) fn target() -> Target {
     base.endian = Endian::Big;
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".into();
-    // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector
-    // ABI. Pass the -vector feature string to LLVM to respect this assumption.
-    base.features = "-vector".into();
     base.max_atomic_width = Some(128);
     base.min_global_align = Some(16);
     base.static_position_independent_executables = true;
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
index a213adadbea..a70cebbd9c8 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
@@ -5,7 +5,8 @@ use crate::spec::{
 pub(crate) fn target() -> Target {
     // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
     let pre_link_args = LinkArgs::new();
-    let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]);
+    let post_link_args =
+        TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0", "-sWASM_BIGINT"]);
 
     let opts = TargetOptions {
         os: "emscripten".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
index 3a3716db350..f42188ec61a 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
     base.vendor = "win7".into();
 
     Target {
-        llvm_target: "x86_64-win7-windows-msvc".into(),
+        llvm_target: "x86_64-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: Some("64-bit Windows 7 support".into()),
             tier: Some(3),
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 88536926b11..112eb862663 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -598,7 +598,12 @@ const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
 const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[/*(64, "zvl64b"), */ (128, "v")];
 // Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
-const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/];
+const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
+
+const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
+const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
+const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
 
 impl super::spec::Target {
     pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
@@ -620,20 +625,24 @@ impl super::spec::Target {
         }
     }
 
-    // Returns None if we do not support ABI checks on the given target yet.
-    pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> {
+    pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
         match &*self.arch {
-            "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors
-            "riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            // FIXME: add support for non-tier2 architectures
-            _ => None,
+            "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors
+            "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "bpf" => &[], // no vector ABI
+            "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
+            // when passing args in vector registers.
+            _ => &[],
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 808e6a50d85..9a7bdaa5b57 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -528,7 +528,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         // Find the method being called.
         let Ok(Some(instance)) = ty::Instance::try_resolve(
             tcx,
-            ctxt.param_env,
+            self.cx.typing_env(ctxt.param_env),
             ctxt.assoc_item.def_id,
             self.cx.resolve_vars_if_possible(ctxt.args),
         ) else {
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 1109b11d2a7..4e7d7b79ff4 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
@@ -2079,7 +2079,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 cand.trait_ref = self
                     .tcx
                     .try_normalize_erasing_regions(
-                        self.tcx.param_env(cand.impl_def_id),
+                        ty::TypingEnv::non_body_analysis(self.tcx, cand.impl_def_id),
                         cand.trait_ref,
                     )
                     .unwrap_or(cand.trait_ref);
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 a5e364d49f7..5ad15feadff 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1075,93 +1075,110 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
         // Autoderef is useful here because sometimes we box callables, etc.
         let Some((def_id_or_name, output, inputs)) =
-            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| {
-                match *found.kind() {
-                    ty::FnPtr(sig_tys, _) => Some((
-                        DefIdOrName::Name("function pointer"),
-                        sig_tys.output(),
-                        sig_tys.inputs(),
-                    )),
-                    ty::FnDef(def_id, _) => {
-                        let fn_sig = found.fn_sig(self.tcx);
-                        Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
-                    }
-                    ty::Closure(def_id, args) => {
-                        let fn_sig = args.as_closure().sig();
-                        Some((
-                            DefIdOrName::DefId(def_id),
-                            fn_sig.output(),
-                            fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
-                        ))
-                    }
-                    ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
-                        self.tcx
-                            .item_super_predicates(def_id)
-                            .instantiate(self.tcx, args)
-                            .iter()
-                            .find_map(|pred| {
-                                if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
-                        && self.tcx.is_lang_item(proj.projection_term.def_id,LangItem::FnOnceOutput)
-                        // args tuple will always be args[1]
-                        && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
-                                {
-                                    Some((
-                                        DefIdOrName::DefId(def_id),
-                                        pred.kind().rebind(proj.term.expect_type()),
-                                        pred.kind().rebind(args.as_slice()),
-                                    ))
-                                } else {
-                                    None
-                                }
-                            })
-                    }
-                    ty::Dynamic(data, _, ty::Dyn) => {
-                        data.iter().find_map(|pred| {
-                            if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() {
+                ty::FnPtr(sig_tys, _) => Some((
+                    DefIdOrName::Name("function pointer"),
+                    sig_tys.output(),
+                    sig_tys.inputs(),
+                )),
+                ty::FnDef(def_id, _) => {
+                    let fn_sig = found.fn_sig(self.tcx);
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+                }
+                ty::Closure(def_id, args) => {
+                    let fn_sig = args.as_closure().sig();
+                    Some((
+                        DefIdOrName::DefId(def_id),
+                        fn_sig.output(),
+                        fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()),
+                    ))
+                }
+                ty::CoroutineClosure(def_id, args) => {
+                    let sig_parts = args.as_coroutine_closure().coroutine_closure_sig();
+                    Some((
+                        DefIdOrName::DefId(def_id),
+                        sig_parts.map_bound(|sig| {
+                            sig.to_coroutine(
+                                self.tcx,
+                                args.as_coroutine_closure().parent_args(),
+                                // Just use infer vars here, since we  don't really care
+                                // what these types are, just that we're returning a coroutine.
+                                self.next_ty_var(DUMMY_SP),
+                                self.tcx.coroutine_for_closure(def_id),
+                                self.next_ty_var(DUMMY_SP),
+                            )
+                        }),
+                        sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),
+                    ))
+                }
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
+                    .tcx
+                    .item_super_predicates(def_id)
+                    .instantiate(self.tcx, args)
+                    .iter()
+                    .find_map(|pred| {
+                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
+                            && self
+                                .tcx
+                                .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
+                            // args tuple will always be args[1]
+                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
+                        {
+                            Some((
+                                DefIdOrName::DefId(def_id),
+                                pred.kind().rebind(proj.term.expect_type()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    }),
+                ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
+                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
                         && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
                         // for existential projection, args are shifted over by 1
                         && let ty::Tuple(args) = proj.args.type_at(0).kind()
-                            {
-                                Some((
-                                    DefIdOrName::Name("trait object"),
-                                    pred.rebind(proj.term.expect_type()),
-                                    pred.rebind(args.as_slice()),
-                                ))
-                            } else {
-                                None
-                            }
-                        })
+                    {
+                        Some((
+                            DefIdOrName::Name("trait object"),
+                            pred.rebind(proj.term.expect_type()),
+                            pred.rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
                     }
-                    ty::Param(param) => {
-                        let generics = self.tcx.generics_of(body_id);
-                        let name = if generics.count() > param.index as usize
-                            && let def = generics.param_at(param.index as usize, self.tcx)
-                            && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
-                            && def.name == param.name
+                }),
+                ty::Param(param) => {
+                    let generics = self.tcx.generics_of(body_id);
+                    let name = if generics.count() > param.index as usize
+                        && let def = generics.param_at(param.index as usize, self.tcx)
+                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
+                        && def.name == param.name
+                    {
+                        DefIdOrName::DefId(def.def_id)
+                    } else {
+                        DefIdOrName::Name("type parameter")
+                    };
+                    param_env.caller_bounds().iter().find_map(|pred| {
+                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
+                            && self
+                                .tcx
+                                .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
+                            && proj.projection_term.self_ty() == found
+                            // args tuple will always be args[1]
+                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
                         {
-                            DefIdOrName::DefId(def.def_id)
+                            Some((
+                                name,
+                                pred.kind().rebind(proj.term.expect_type()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
                         } else {
-                            DefIdOrName::Name("type parameter")
-                        };
-                        param_env.caller_bounds().iter().find_map(|pred| {
-                            if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
-                        && self.tcx.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
-                        && proj.projection_term.self_ty() == found
-                        // args tuple will always be args[1]
-                        && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
-                            {
-                                Some((
-                                    name,
-                                    pred.kind().rebind(proj.term.expect_type()),
-                                    pred.kind().rebind(args.as_slice()),
-                                ))
-                            } else {
-                                None
-                            }
-                        })
-                    }
-                    _ => None,
+                            None
+                        }
+                    })
                 }
+                _ => None,
             })
         else {
             return None;
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 8f1c8a29663..43244eb5dcb 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -32,8 +32,10 @@ impl<'tcx> InferCtxt<'tcx> {
     fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         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 !(param_env, ty).has_infer() {
-            return ty.is_copy_modulo_regions(self.tcx, param_env);
+            return ty.is_copy_modulo_regions(self.tcx, self.typing_env(param_env));
         }
 
         let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 103f7c76a86..fac0414d714 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -9,7 +9,6 @@ use rustc_data_structures::unord::UnordSet;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::ty::{Region, RegionVid};
 use tracing::debug;
-use ty::TypingMode;
 
 use super::*;
 use crate::errors::UnableToConstructConstantValue;
@@ -71,7 +70,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     pub fn find_auto_trait_generics<A>(
         &self,
         ty: Ty<'tcx>,
-        orig_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         trait_did: DefId,
         mut auto_trait_callback: impl FnMut(AutoTraitInfo<'tcx>) -> A,
     ) -> AutoTraitResult<A> {
@@ -79,7 +78,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
         let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]);
 
-        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
+        let (infcx, orig_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
         let mut selcx = SelectionContext::new(&infcx);
         for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
             let result = selcx.select(&Obligation::new(
@@ -89,17 +88,13 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 ty::TraitPredicate { trait_ref, polarity },
             ));
             if let Ok(Some(ImplSource::UserDefined(_))) = result {
-                debug!(
-                    "find_auto_trait_generics({:?}): \
-                 manual impl found, bailing out",
-                    trait_ref
-                );
+                debug!("find_auto_trait_generics({trait_ref:?}): manual impl found, bailing out");
                 // If an explicit impl exists, it always takes priority over an auto impl
                 return AutoTraitResult::ExplicitImpl;
             }
         }
 
-        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
+        let (infcx, orig_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
         let mut fresh_preds = FxIndexSet::default();
 
         // Due to the way projections are handled by SelectionContext, we need to run
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index c00246cfd7d..cf63f14fb93 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -513,7 +513,7 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method:
 
     let method_def_id = method.def_id;
     let sig = tcx.fn_sig(method_def_id).instantiate_identity();
-    let param_env = tcx.param_env(method_def_id);
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, method_def_id);
     let receiver_ty = tcx.liberate_late_bound_regions(method_def_id, sig.input(0));
 
     if receiver_ty == tcx.types.self_param {
@@ -523,7 +523,7 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method:
 
     // e.g., `Rc<()>`
     let unit_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method_def_id);
-    match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.backend_repr) {
+    match tcx.layout_of(typing_env.as_query_input(unit_receiver_ty)).map(|l| l.backend_repr) {
         Ok(BackendRepr::Scalar(..)) => (),
         abi => {
             tcx.dcx().span_delayed_bug(
@@ -538,7 +538,7 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method:
     // e.g., `Rc<dyn Trait>`
     let trait_object_receiver =
         receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method_def_id);
-    match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.backend_repr) {
+    match tcx.layout_of(typing_env.as_query_input(trait_object_receiver)).map(|l| l.backend_repr) {
         Ok(BackendRepr::ScalarPair(..)) => (),
         abi => {
             tcx.dcx().span_delayed_bug(
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index fe90066b4e7..80cef690028 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -611,11 +611,12 @@ pub fn try_evaluate_const<'tcx>(
             //
             // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
             // instead of having this logic here
-            let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx);
+            let typing_env =
+                tcx.erase_regions(infcx.typing_env(param_env)).with_reveal_all_normalized(tcx);
             let erased_uv = tcx.erase_regions(uv);
 
             use rustc_middle::mir::interpret::ErrorHandled;
-            match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) {
+            match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
                 Ok(Ok(val)) => Ok(ty::Const::new_value(
                     tcx,
                     val,
@@ -697,8 +698,8 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
 /// used during analysis.
 pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool {
     debug!("impossible_predicates(predicates={:?})", predicates);
-    let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
-    let param_env = ty::ParamEnv::reveal_all();
+    let (infcx, param_env) =
+        tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
     let ocx = ObligationCtxt::new(&infcx);
     let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates);
     for predicate in predicates {
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 4ff0910c9b9..1d3e8d43af7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -144,7 +144,14 @@ pub fn compute_dropck_outlives_inner<'tcx>(
             result.overflows.len(),
             ty_stack.len()
         );
-        dtorck_constraint_for_ty_inner(tcx, param_env, DUMMY_SP, depth, ty, &mut constraints)?;
+        dtorck_constraint_for_ty_inner(
+            tcx,
+            ocx.infcx.typing_env(param_env),
+            DUMMY_SP,
+            depth,
+            ty,
+            &mut constraints,
+        )?;
 
         // "outlives" represent types/regions that may be touched
         // by a destructor.
@@ -196,10 +203,10 @@ pub fn compute_dropck_outlives_inner<'tcx>(
 
 /// Returns a set of constraints that needs to be satisfied in
 /// order for `ty` to be valid for destruction.
-#[instrument(level = "debug", skip(tcx, param_env, span, constraints))]
+#[instrument(level = "debug", skip(tcx, typing_env, span, constraints))]
 pub fn dtorck_constraint_for_ty_inner<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     span: Span,
     depth: usize,
     ty: Ty<'tcx>,
@@ -234,20 +241,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
         ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
             // single-element containers, behave like their element
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)
+                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints)
             })?;
         }
 
         ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
             for ty in tys.iter() {
-                dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?;
+                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?;
             }
             Ok::<_, NoSolution>(())
         })?,
 
         ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
             for ty in args.as_closure().upvar_tys() {
-                dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?;
+                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?;
             }
             Ok::<_, NoSolution>(())
         })?,
@@ -257,7 +264,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
                 for ty in args.as_coroutine_closure().upvar_tys() {
                     dtorck_constraint_for_ty_inner(
                         tcx,
-                        param_env,
+                        typing_env,
                         span,
                         depth + 1,
                         ty,
@@ -296,7 +303,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             // While we conservatively assume that all coroutines require drop
             // to avoid query cycles during MIR building, we can check the actual
             // witness during borrowck to avoid unnecessary liveness constraints.
-            if args.witness().needs_drop(tcx, tcx.erase_regions(param_env)) {
+            if args.witness().needs_drop(tcx, tcx.erase_regions(typing_env)) {
                 constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
                 constraints.outlives.push(args.resume_ty().into());
             }
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 bf3f83ec827..345e1cc31f3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -111,8 +111,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::Tuple) {
                 self.assemble_candidate_for_tuple(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::PointerLike) {
-                self.assemble_candidate_for_pointer_like(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
                 self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
             } else {
@@ -1216,31 +1214,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    fn assemble_candidate_for_pointer_like(
-        &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) {
-        // The regions of a type don't affect the size of the type
-        let tcx = self.tcx();
-        let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty());
-        // We should erase regions from both the param-env and type, since both
-        // may have infer regions. Specifically, after canonicalizing and instantiating,
-        // early bound regions turn into region vars in both the new and old solver.
-        let key = tcx.erase_regions(obligation.param_env.and(self_ty));
-        // But if there are inference variables, we have to wait until it's resolved.
-        if key.has_non_region_infer() {
-            candidates.ambiguous = true;
-            return;
-        }
-
-        if let Ok(layout) = tcx.layout_of(key)
-            && layout.layout.is_pointer_like(&tcx.data_layout)
-        {
-            candidates.vec.push(BuiltinCandidate { has_nested: false });
-        }
-    }
-
     fn assemble_candidates_for_fn_ptr_trait(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index bb56d6eaf54..b5bc8364c7b 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -9,8 +9,7 @@ use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast,
-    VtblEntry,
+    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
 };
 use rustc_span::{DUMMY_SP, Span, sym};
 use smallvec::{SmallVec, smallvec};
@@ -276,8 +275,10 @@ fn vtable_entries<'tcx>(
                     // The trait type may have higher-ranked lifetimes in it;
                     // erase them if they appear, so that we get the type
                     // at some particular call site.
-                    let args =
-                        tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), args);
+                    let args = tcx.normalize_erasing_late_bound_regions(
+                        ty::TypingEnv::fully_monomorphized(),
+                        args,
+                    );
 
                     // It's possible that the method relies on where-clauses that
                     // do not hold for this particular set of type parameters.
@@ -294,7 +295,7 @@ fn vtable_entries<'tcx>(
 
                     let instance = ty::Instance::expect_resolve_for_vtable(
                         tcx,
-                        ty::ParamEnv::reveal_all(),
+                        ty::TypingEnv::fully_monomorphized(),
                         def_id,
                         args,
                         DUMMY_SP,
@@ -440,8 +441,8 @@ fn trait_refs_are_compatible<'tcx>(
         return false;
     }
 
-    let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
-    let param_env = ty::ParamEnv::reveal_all();
+    let (infcx, param_env) =
+        tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
     let ocx = ObligationCtxt::new(&infcx);
     let hr_source_principal =
         ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal);
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index d8c1c50d79a..57225df0819 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -6,7 +6,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::traits::CodegenObligationError;
-use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
@@ -23,14 +23,15 @@ use tracing::debug;
 /// This also expects that `trait_ref` is fully normalized.
 pub(crate) fn codegen_select_candidate<'tcx>(
     tcx: TyCtxt<'tcx>,
-    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>),
+    key: PseudoCanonicalInput<'tcx, ty::TraitRef<'tcx>>,
 ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
+    let PseudoCanonicalInput { typing_env, value: trait_ref } = key;
     // We expect the input to be fully normalized.
-    debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
+    debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(typing_env, trait_ref));
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env));
+    let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
     let mut selcx = SelectionContext::new(&infcx);
 
     let obligation_cause = ObligationCause::dummy();
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 4e5309eea28..51e4dbe81b3 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -5,7 +5,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
-use rustc_middle::ty::{GenericArgs, TyCtxt};
+use rustc_middle::ty::{self, GenericArgs, TyCtxt};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::dropck_outlives::{
     compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
@@ -35,7 +35,7 @@ pub(crate) fn adt_dtorck_constraint(
 ) -> Result<&DropckConstraint<'_>, NoSolution> {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
-    let param_env = tcx.param_env(def_id);
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
     debug!("dtorck_constraint: {:?}", def);
 
     if def.is_manually_drop() {
@@ -57,7 +57,7 @@ pub(crate) fn adt_dtorck_constraint(
     let mut result = DropckConstraint::empty();
     for field in def.all_fields() {
         let fty = tcx.type_of(field.did).instantiate_identity();
-        dtorck_constraint_for_ty_inner(tcx, param_env, span, 0, fty, &mut result)?;
+        dtorck_constraint_for_ty_inner(tcx, typing_env, span, 0, fty, &mut result)?;
     }
     result.outlives.extend(tcx.destructor_constraints(def));
     dedup_dtorck_constraint(&mut result);
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index d79059a39a1..68ff66bbce7 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -1,7 +1,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Normalized, ObligationCause};
 use tracing::debug;
@@ -19,10 +19,10 @@ pub(crate) fn provide(p: &mut Providers) {
 
 fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy>(
     tcx: TyCtxt<'tcx>,
-    goal: ParamEnvAnd<'tcx, T>,
+    goal: PseudoCanonicalInput<'tcx, T>,
 ) -> Result<T, NoSolution> {
-    let ParamEnvAnd { param_env, value } = goal;
-    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
+    let PseudoCanonicalInput { typing_env, value } = goal;
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
     let cause = ObligationCause::dummy();
     match infcx.at(&cause, param_env).query_normalize(value) {
         Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 9dabcea706f..023c8fad781 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -31,7 +31,7 @@ where
 #[cfg(feature = "rustc")]
 mod rustc {
     use rustc_middle::ty::layout::LayoutCx;
-    use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+    use rustc_middle::ty::{Ty, TyCtxt, TypingEnv};
 
     use super::*;
     use crate::layout::tree::rustc::Err;
@@ -43,7 +43,7 @@ mod rustc {
         pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
             let Self { src, dst, assume, context } = self;
 
-            let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all());
+            let layout_cx = LayoutCx::new(context, TypingEnv::fully_monomorphized());
 
             // Convert `src` and `dst` from their rustc representations, to `Tree`-based
             // representations.
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 0184e93acf1..a5a9125c8b5 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -7,7 +7,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{
-    FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind,
+    FnAbiError, HasTyCtxt, HasTypingEnv, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind,
 };
 use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt};
 use rustc_session::config::OptLevel;
@@ -26,11 +26,11 @@ pub(crate) fn provide(providers: &mut Providers) {
 // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
 // or should go through `FnAbi` instead, to avoid losing any
 // adjustments `fn_abi_of_instance` might be performing.
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[tracing::instrument(level = "debug", skip(tcx, typing_env))]
 fn fn_sig_for_fn_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 ) -> ty::PolyFnSig<'tcx> {
     if let InstanceKind::ThreadLocalShim(..) = instance.def {
         return ty::Binder::dummy(tcx.mk_fn_sig(
@@ -42,7 +42,7 @@ fn fn_sig_for_fn_abi<'tcx>(
         ));
     }
 
-    let ty = instance.ty(tcx, param_env);
+    let ty = instance.ty(tcx, typing_env);
     match *ty.kind() {
         ty::FnDef(..) => {
             // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
@@ -56,7 +56,10 @@ fn fn_sig_for_fn_abi<'tcx>(
                 ty::FnDef(def_id, args) => tcx
                     .fn_sig(def_id)
                     .map_bound(|fn_sig| {
-                        tcx.normalize_erasing_regions(tcx.param_env(def_id), fn_sig)
+                        tcx.normalize_erasing_regions(
+                            ty::TypingEnv::non_body_analysis(tcx, def_id),
+                            fn_sig,
+                        )
                     })
                     .instantiate(tcx, args),
                 _ => unreachable!(),
@@ -329,27 +332,26 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv
 
 fn fn_abi_of_fn_ptr<'tcx>(
     tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+    query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
 ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
-    let (param_env, (sig, extra_args)) = query.into_parts();
-
-    let cx = LayoutCx::new(tcx, param_env);
+    let ty::PseudoCanonicalInput { typing_env, value: (sig, extra_args) } = query;
+    let cx = LayoutCx::new(tcx, typing_env);
     fn_abi_new_uncached(&cx, sig, extra_args, None, None, false)
 }
 
 fn fn_abi_of_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+    query: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
 ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
-    let (param_env, (instance, extra_args)) = query.into_parts();
+    let ty::PseudoCanonicalInput { typing_env, value: (instance, extra_args) } = query;
 
-    let sig = fn_sig_for_fn_abi(tcx, instance, param_env);
+    let sig = fn_sig_for_fn_abi(tcx, instance, typing_env);
 
     let caller_location =
         instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty());
 
     fn_abi_new_uncached(
-        &LayoutCx::new(tcx, param_env),
+        &LayoutCx::new(tcx, typing_env),
         sig,
         extra_args,
         caller_location,
@@ -395,7 +397,7 @@ fn adjust_for_rust_scalar<'tcx>(
             Some(kind)
         } else if let Some(pointee) = drop_target_pointee {
             // The argument to `drop_in_place` is semantically equivalent to a mutable reference.
-            Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.param_env()) })
+            Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.typing_env) })
         } else {
             None
         };
@@ -542,7 +544,7 @@ fn fn_abi_sanity_check<'tcx>(
                 // With metadata. Must be unsized and not on the stack.
                 assert!(arg.layout.is_unsized() && !on_stack);
                 // Also, must not be `extern` type.
-                let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
+                let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.typing_env);
                 if matches!(tail.kind(), ty::Foreign(..)) {
                     // These types do not have metadata, so having `meta_attrs` is bogus.
                     // Conceptually, unsized arguments must be copied around, which requires dynamically
@@ -573,7 +575,7 @@ fn fn_abi_new_uncached<'tcx>(
     force_thin_self_ptr: bool,
 ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
     let tcx = cx.tcx();
-    let sig = tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
+    let sig = tcx.normalize_erasing_late_bound_regions(cx.typing_env, sig);
 
     let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
 
@@ -744,7 +746,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
 
 #[tracing::instrument(level = "debug", skip(cx))]
 fn make_thin_self_ptr<'tcx>(
-    cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
+    cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>),
     layout: TyAndLayout<'tcx>,
 ) -> TyAndLayout<'tcx> {
     let tcx = cx.tcx();
@@ -784,6 +786,6 @@ fn make_thin_self_ptr<'tcx>(
 
         // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
         // should always work because the type is always `*mut ()`.
-        ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+        ..tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(unit_ptr_ty)).unwrap()
     }
 }
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index c26b41d8960..2157ab3c402 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -3,34 +3,33 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_trait_selection::traits;
 
-fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
     is_item_raw(tcx, query, LangItem::Copy)
 }
 
-fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
     is_item_raw(tcx, query, LangItem::Sized)
 }
 
-fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
     is_item_raw(tcx, query, LangItem::Freeze)
 }
 
-fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
     is_item_raw(tcx, query, LangItem::Unpin)
 }
 
 fn is_item_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
     item: LangItem,
 ) -> bool {
-    let (param_env, ty) = query.into_parts();
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env);
     let trait_def_id = tcx.require_lang_item(item, None);
-    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
-    traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id)
+    traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id)
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 1d8a0880760..29fc92e1f2f 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -6,29 +6,31 @@ use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
 use rustc_middle::ty::util::AsyncDropGlueMorphology;
-use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{
+    self, GenericArgsRef, Instance, PseudoCanonicalInput, TyCtxt, TypeVisitableExt,
+};
 use rustc_span::sym;
 use rustc_trait_selection::traits;
 use rustc_type_ir::ClosureKind;
 use tracing::debug;
-use traits::{Reveal, translate_args};
+use traits::translate_args;
 
 use crate::errors::UnexpectedFnPtrAssociatedItem;
 
 fn resolve_instance_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>,
+    key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)>,
 ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
-    let (param_env, (def_id, args)) = key.into_parts();
+    let PseudoCanonicalInput { typing_env, value: (def_id, args) } = key;
 
     let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
-        debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
+        debug!(" => associated item, attempting to find impl in typing_env {:#?}", typing_env);
         resolve_associated_item(
             tcx,
             def_id,
-            param_env,
+            typing_env,
             trait_def_id,
-            tcx.normalize_erasing_regions(param_env, args),
+            tcx.normalize_erasing_regions(typing_env, args),
         )
     } else {
         let def = if tcx.intrinsic(def_id).is_some() {
@@ -37,7 +39,7 @@ fn resolve_instance_raw<'tcx>(
         } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) {
             let ty = args.type_at(0);
 
-            if ty.needs_drop(tcx, param_env) {
+            if ty.needs_drop(tcx, typing_env) {
                 debug!(" => nontrivial drop glue");
                 match *ty.kind() {
                     ty::Closure(..)
@@ -93,15 +95,16 @@ fn resolve_instance_raw<'tcx>(
 fn resolve_associated_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_item_id: DefId,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     trait_id: DefId,
     rcvr_args: GenericArgsRef<'tcx>,
 ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
-    debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_args, "resolve_associated_item");
+    debug!(?trait_item_id, ?typing_env, ?trait_id, ?rcvr_args, "resolve_associated_item");
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args);
 
-    let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) {
+    let input = typing_env.as_query_input(trait_ref);
+    let vtbl = match tcx.codegen_select_candidate(input) {
         Ok(vtbl) => vtbl,
         Err(
             CodegenObligationError::Ambiguity
@@ -116,7 +119,7 @@ fn resolve_associated_item<'tcx>(
         traits::ImplSource::UserDefined(impl_data) => {
             debug!(
                 "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
-                param_env, trait_item_id, rcvr_args, impl_data
+                typing_env, trait_item_id, rcvr_args, impl_data
             );
             assert!(!rcvr_args.has_infer());
             assert!(!trait_ref.has_infer());
@@ -129,17 +132,6 @@ fn resolve_associated_item<'tcx>(
                 .unwrap_or_else(|| {
                     bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
                 });
-            let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
-            let param_env = param_env.with_reveal_all_normalized(tcx);
-            let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args);
-            let args = translate_args(
-                &infcx,
-                param_env,
-                impl_data.impl_def_id,
-                args,
-                leaf_def.defining_node,
-            );
-            let args = infcx.tcx.erase_regions(args);
 
             // Since this is a trait item, we need to see if the item is either a trait default item
             // or a specialization because we can't resolve those unless we can `Reveal::All`.
@@ -153,16 +145,28 @@ fn resolve_associated_item<'tcx>(
                 // and the obligation is monomorphic, otherwise passes such as
                 // transmute checking and polymorphic MIR optimizations could
                 // get a result which isn't correct for all monomorphizations.
-                if param_env.reveal() == Reveal::All {
-                    !trait_ref.still_further_specializable()
-                } else {
-                    false
+                match typing_env.typing_mode {
+                    ty::TypingMode::Coherence
+                    | ty::TypingMode::Analysis { defining_opaque_types: _ } => false,
+                    ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
                 }
             };
             if !eligible {
                 return Ok(None);
             }
 
+            let typing_env = typing_env.with_reveal_all_normalized(tcx);
+            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+            let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args);
+            let args = translate_args(
+                &infcx,
+                param_env,
+                impl_data.impl_def_id,
+                args,
+                leaf_def.defining_node,
+            );
+            let args = infcx.tcx.erase_regions(args);
+
             // HACK: We may have overlapping `dyn Trait` built-in impls and
             // user-provided blanket impls. Detect that case here, and return
             // ambiguity.
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 63421dfdce6..092e140a600 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -19,7 +19,8 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
+    self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
+    TypeVisitableExt,
 };
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use rustc_span::sym;
@@ -40,22 +41,22 @@ pub(crate) fn provide(providers: &mut Providers) {
 #[instrument(skip(tcx, query), level = "debug")]
 fn layout_of<'tcx>(
     tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
 ) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> {
-    let (param_env, ty) = query.into_parts();
+    let PseudoCanonicalInput { typing_env, value: ty } = query;
     debug!(?ty);
 
     // Optimization: We convert to RevealAll and convert opaque types in the where bounds
     // to their hidden types. This reduces overall uncached invocations of `layout_of` and
     // is thus a small performance improvement.
-    let param_env = param_env.with_reveal_all_normalized(tcx);
+    let typing_env = typing_env.with_reveal_all_normalized(tcx);
     let unnormalized_ty = ty;
 
     // FIXME: We might want to have two different versions of `layout_of`:
     // One that can be called after typecheck has completed and can use
     // `normalize_erasing_regions` here and another one that can be called
     // before typecheck has completed and uses `try_normalize_erasing_regions`.
-    let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+    let ty = match tcx.try_normalize_erasing_regions(typing_env, ty) {
         Ok(t) => t,
         Err(normalization_error) => {
             return Err(tcx
@@ -66,10 +67,10 @@ fn layout_of<'tcx>(
 
     if ty != unnormalized_ty {
         // Ensure this layout is also cached for the normalized type.
-        return tcx.layout_of(param_env.and(ty));
+        return tcx.layout_of(typing_env.as_query_input(ty));
     }
 
-    let cx = LayoutCx::new(tcx, param_env);
+    let cx = LayoutCx::new(tcx, typing_env);
 
     let layout = layout_of_uncached(&cx, ty)?;
     let layout = TyAndLayout { ty, layout };
@@ -104,7 +105,7 @@ fn map_error<'tcx>(
             // This is sometimes not a compile error if there are trivially false where clauses.
             // See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
             assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
-            if !field.ty.is_sized(cx.tcx(), cx.param_env) {
+            if !field.ty.is_sized(cx.tcx(), cx.typing_env) {
                 cx.tcx().dcx().delayed_bug(format!(
                     "encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
                 ));
@@ -152,7 +153,6 @@ fn layout_of_uncached<'tcx>(
     }
 
     let tcx = cx.tcx();
-    let param_env = cx.param_env;
     let dl = cx.data_layout();
     let scalar_unit = |value: Primitive| {
         let size = value.size(dl);
@@ -178,12 +178,12 @@ fn layout_of_uncached<'tcx>(
                     {
                         if let Some(start) = start {
                             scalar.valid_range_mut().start = start
-                                .try_to_bits(tcx, param_env)
+                                .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                         }
                         if let Some(end) = end {
                             let mut end = end
-                                .try_to_bits(tcx, param_env)
+                                .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                             if !include_end {
                                 end = end.wrapping_sub(1);
@@ -235,8 +235,8 @@ fn layout_of_uncached<'tcx>(
                 data_ptr.valid_range_mut().start = 1;
             }
 
-            let pointee = tcx.normalize_erasing_regions(param_env, pointee);
-            if pointee.is_sized(tcx, param_env) {
+            let pointee = tcx.normalize_erasing_regions(cx.typing_env, pointee);
+            if pointee.is_sized(tcx, cx.typing_env) {
                 return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
             }
 
@@ -247,7 +247,7 @@ fn layout_of_uncached<'tcx>(
             {
                 let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
                 let metadata_ty =
-                    match tcx.try_normalize_erasing_regions(param_env, pointee_metadata) {
+                    match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) {
                         Ok(metadata_ty) => metadata_ty,
                         Err(mut err) => {
                             // Usually `<Ty as Pointee>::Metadata` can't be normalized because
@@ -259,7 +259,7 @@ fn layout_of_uncached<'tcx>(
                             // that is an alias, which is likely the cause of the normalization
                             // error.
                             match tcx.try_normalize_erasing_regions(
-                                param_env,
+                                cx.typing_env,
                                 tcx.struct_tail_raw(pointee, |ty| ty, || {}),
                             ) {
                                 Ok(_) => {}
@@ -283,7 +283,7 @@ fn layout_of_uncached<'tcx>(
 
                 metadata
             } else {
-                let unsized_part = tcx.struct_tail_for_codegen(pointee, param_env);
+                let unsized_part = tcx.struct_tail_for_codegen(pointee, cx.typing_env);
 
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
@@ -316,7 +316,7 @@ fn layout_of_uncached<'tcx>(
         // Arrays and slices.
         ty::Array(element, mut count) => {
             if count.has_aliases() {
-                count = tcx.normalize_erasing_regions(param_env, count);
+                count = tcx.normalize_erasing_regions(cx.typing_env, count);
                 if count.has_aliases() {
                     return Err(error(cx, LayoutError::Unknown(ty)));
                 }
@@ -331,7 +331,7 @@ fn layout_of_uncached<'tcx>(
                 .checked_mul(count, dl)
                 .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
 
-            let abi = if count != 0 && ty.is_privately_uninhabited(tcx, param_env) {
+            let abi = if count != 0 && ty.is_privately_uninhabited(tcx, cx.typing_env) {
                 BackendRepr::Uninhabited
             } else {
                 BackendRepr::Memory { sized: true }
@@ -594,8 +594,8 @@ fn layout_of_uncached<'tcx>(
 
             let maybe_unsized = def.is_struct()
                 && def.non_enum_variant().tail_opt().is_some_and(|last_field| {
-                    let param_env = tcx.param_env(def.did());
-                    !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, param_env)
+                    let typing_env = ty::TypingEnv::post_analysis(tcx, def.did());
+                    !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, typing_env)
                 });
 
             let layout = cx
@@ -620,7 +620,7 @@ fn layout_of_uncached<'tcx>(
             // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
             if cfg!(debug_assertions)
                 && maybe_unsized
-                && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.param_env)
+                && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.typing_env)
             {
                 let mut variants = variants;
                 let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
@@ -1024,7 +1024,7 @@ fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tc
     // Ignore layouts that are done with non-empty environments or
     // non-monomorphic layouts, as the user only wants to see the stuff
     // resulting from the final codegen session.
-    if layout.ty.has_non_region_param() || !cx.param_env.caller_bounds().is_empty() {
+    if layout.ty.has_non_region_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
         return;
     }
 
diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs
index fc05dd8256b..26ea81daf78 100644
--- a/compiler/rustc_ty_utils/src/layout/invariant.rs
+++ b/compiler/rustc_ty_utils/src/layout/invariant.rs
@@ -9,7 +9,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa
     let tcx = cx.tcx();
 
     // Type-level uninhabitedness should always imply ABI uninhabitedness.
-    if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
+    if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) {
         assert!(layout.is_uninhabited());
     }
 
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 5fecbd310b7..469a4ac3e41 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -8,20 +8,23 @@ use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components};
 use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt};
 use rustc_session::Limit;
 use rustc_span::sym;
-use tracing::debug;
+use tracing::{debug, instrument};
 
 use crate::errors::NeedsDropOverflow;
 
 type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
 
-fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+fn needs_drop_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
+) -> bool {
     // If we don't know a type doesn't need drop, for example if it's a type
     // parameter without a `Copy` bound, then we conservatively return that it
     // needs drop.
     let adt_has_dtor =
         |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant);
-    let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false)
-        .filter(filter_array_elements(tcx, query.param_env))
+    let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_dtor, false, false)
+        .filter(filter_array_elements(tcx, query.typing_env))
         .next()
         .is_some();
 
@@ -29,14 +32,17 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
     res
 }
 
-fn needs_async_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+fn needs_async_drop_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
+) -> bool {
     // If we don't know a type doesn't need async drop, for example if it's a
     // type parameter without a `Copy` bound, then we conservatively return that
     // it needs async drop.
     let adt_has_async_dtor =
         |adt_def: ty::AdtDef<'tcx>| adt_def.async_destructor(tcx).map(|_| DtorType::Significant);
-    let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_async_dtor, false)
-        .filter(filter_array_elements(tcx, query.param_env))
+    let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false, false)
+        .filter(filter_array_elements(tcx, query.typing_env))
         .next()
         .is_some();
 
@@ -50,11 +56,11 @@ fn needs_async_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty
 /// logic that is easier to follow while not repeating any checks that may thus diverge.
 fn filter_array_elements<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
 ) -> impl Fn(&Result<Ty<'tcx>, AlwaysRequiresDrop>) -> bool {
     move |ty| match ty {
         Ok(ty) => match *ty.kind() {
-            ty::Array(elem, _) => tcx.needs_drop_raw(param_env.and(elem)),
+            ty::Array(elem, _) => tcx.needs_drop_raw(typing_env.as_query_input(elem)),
             _ => true,
         },
         Err(AlwaysRequiresDrop) => true,
@@ -63,16 +69,17 @@ fn filter_array_elements<'tcx>(
 
 fn has_significant_drop_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
 ) -> bool {
     let res = drop_tys_helper(
         tcx,
         query.value,
-        query.param_env,
+        query.typing_env,
         adt_consider_insignificant_dtor(tcx),
         true,
+        false,
     )
-    .filter(filter_array_elements(tcx, query.param_env))
+    .filter(filter_array_elements(tcx, query.typing_env))
     .next()
     .is_some();
     debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
@@ -81,9 +88,9 @@ fn has_significant_drop_raw<'tcx>(
 
 struct NeedsDropTypes<'tcx, F> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    // Whether to reveal coroutine witnesses, this is set
-    // to `false` unless we compute `needs_drop` for a coroutine witness.
+    typing_env: ty::TypingEnv<'tcx>,
+    /// Whether to reveal coroutine witnesses, this is set
+    /// to `false` unless we compute `needs_drop` for a coroutine witness.
     reveal_coroutine_witnesses: bool,
     query_ty: Ty<'tcx>,
     seen_tys: FxHashSet<Ty<'tcx>>,
@@ -94,28 +101,40 @@ struct NeedsDropTypes<'tcx, F> {
     unchecked_tys: Vec<(Ty<'tcx>, usize)>,
     recursion_limit: Limit,
     adt_components: F,
+    /// Set this to true if an exhaustive list of types involved in
+    /// drop obligation is requested.
+    exhaustive: bool,
 }
 
 impl<'tcx, F> NeedsDropTypes<'tcx, F> {
     fn new(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ty: Ty<'tcx>,
+        exhaustive: bool,
         adt_components: F,
     ) -> Self {
         let mut seen_tys = FxHashSet::default();
         seen_tys.insert(ty);
         Self {
             tcx,
-            param_env,
-            reveal_coroutine_witnesses: false,
+            typing_env,
+            reveal_coroutine_witnesses: exhaustive,
             seen_tys,
             query_ty: ty,
             unchecked_tys: vec![(ty, 0)],
             recursion_limit: tcx.recursion_limit(),
             adt_components,
+            exhaustive,
         }
     }
+
+    /// Called when `ty` is found to always require drop.
+    /// If the exhaustive flag is true, then `Ok(ty)` is returned like any other type.
+    /// Otherwise, `Err(AlwaysRequireDrop)` is returned, which will cause iteration to abort.
+    fn always_drop_component(&self, ty: Ty<'tcx>) -> NeedsDropResult<Ty<'tcx>> {
+        if self.exhaustive { Ok(ty) } else { Err(AlwaysRequiresDrop) }
+    }
 }
 
 impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
@@ -125,19 +144,22 @@ where
 {
     type Item = NeedsDropResult<Ty<'tcx>>;
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
         let tcx = self.tcx;
 
         while let Some((ty, level)) = self.unchecked_tys.pop() {
+            debug!(?ty, "needs_drop_components: inspect");
             if !self.recursion_limit.value_within_limit(level) {
                 // Not having a `Span` isn't great. But there's hopefully some other
                 // recursion limit error as well.
+                debug!("needs_drop_components: recursion limit exceeded");
                 tcx.dcx().emit_err(NeedsDropOverflow { query_ty: self.query_ty });
-                return Some(Err(AlwaysRequiresDrop));
+                return Some(self.always_drop_component(ty));
             }
 
             let components = match needs_drop_components(tcx, ty) {
-                Err(e) => return Some(Err(e)),
+                Err(AlwaysRequiresDrop) => return Some(self.always_drop_component(ty)),
                 Ok(components) => components,
             };
             debug!("needs_drop_components({:?}) = {:?}", ty, components);
@@ -165,7 +187,7 @@ where
                         if self.reveal_coroutine_witnesses {
                             queue_type(self, args.as_coroutine().witness());
                         } else {
-                            return Some(Err(AlwaysRequiresDrop));
+                            return Some(self.always_drop_component(ty));
                         }
                     }
                     ty::CoroutineWitness(def_id, args) => {
@@ -180,7 +202,7 @@ where
                         }
                     }
 
-                    _ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
+                    _ if component.is_copy_modulo_regions(tcx, self.typing_env) => {}
 
                     ty::Closure(_, args) => {
                         for upvar in args.as_closure().upvar_tys() {
@@ -199,12 +221,14 @@ where
                     // impl then check whether the field types need `Drop`.
                     ty::Adt(adt_def, args) => {
                         let tys = match (self.adt_components)(adt_def, args) {
-                            Err(e) => return Some(Err(e)),
+                            Err(AlwaysRequiresDrop) => {
+                                return Some(self.always_drop_component(ty));
+                            }
                             Ok(tys) => tys,
                         };
                         for required_ty in tys {
                             let required = tcx
-                                .try_normalize_erasing_regions(self.param_env, required_ty)
+                                .try_normalize_erasing_regions(self.typing_env, required_ty)
                                 .unwrap_or(required_ty);
 
                             queue_type(self, required);
@@ -224,7 +248,8 @@ where
                     }
 
                     ty::Foreign(_) | ty::Dynamic(..) => {
-                        return Some(Err(AlwaysRequiresDrop));
+                        debug!("needs_drop_components: foreign or dynamic");
+                        return Some(self.always_drop_component(ty));
                     }
 
                     ty::Bool
@@ -271,9 +296,10 @@ enum DtorType {
 fn drop_tys_helper<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
-    param_env: rustc_middle::ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     adt_has_dtor: impl Fn(ty::AdtDef<'tcx>) -> Option<DtorType>,
     only_significant: bool,
+    exhaustive: bool,
 ) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
     fn with_query_cache<'tcx>(
         tcx: TyCtxt<'tcx>,
@@ -337,7 +363,7 @@ fn drop_tys_helper<'tcx>(
         .map(|v| v.into_iter())
     };
 
-    NeedsDropTypes::new(tcx, param_env, ty, adt_components)
+    NeedsDropTypes::new(tcx, typing_env, ty, exhaustive, adt_components)
 }
 
 fn adt_consider_insignificant_dtor<'tcx>(
@@ -375,9 +401,10 @@ fn adt_drop_tys<'tcx>(
     drop_tys_helper(
         tcx,
         tcx.type_of(def_id).instantiate_identity(),
-        tcx.param_env(def_id),
+        ty::TypingEnv::non_body_analysis(tcx, def_id),
         adt_has_dtor,
         false,
+        false,
     )
     .collect::<Result<Vec<_>, _>>()
     .map(|components| tcx.mk_type_list(&components))
@@ -392,14 +419,34 @@ fn adt_significant_drop_tys(
     drop_tys_helper(
         tcx,
         tcx.type_of(def_id).instantiate_identity(), // identical to `tcx.make_adt(def, identity_args)`
-        tcx.param_env(def_id),
+        ty::TypingEnv::non_body_analysis(tcx, def_id),
         adt_consider_insignificant_dtor(tcx),
         true,
+        false,
     )
     .collect::<Result<Vec<_>, _>>()
     .map(|components| tcx.mk_type_list(&components))
 }
 
+#[instrument(level = "debug", skip(tcx), ret)]
+fn list_significant_drop_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> &'tcx ty::List<Ty<'tcx>> {
+    tcx.mk_type_list(
+        &drop_tys_helper(
+            tcx,
+            ty.value,
+            ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: ty.param_env },
+            adt_consider_insignificant_dtor(tcx),
+            true,
+            true,
+        )
+        .filter_map(|res| res.ok())
+        .collect::<Vec<_>>(),
+    )
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         needs_drop_raw,
@@ -407,6 +454,7 @@ pub(crate) fn provide(providers: &mut Providers) {
         has_significant_drop_raw,
         adt_drop_tys,
         adt_significant_drop_tys,
+        list_significant_drop_tys,
         ..*providers
     };
 }
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 3fbce7886ed..2c1ad9de9aa 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -157,7 +157,7 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
             }
             // `T: ~const Trait` implies `T: ~const Supertrait`.
             ty::ClauseKind::HostEffect(data) => self.extend_deduped(
-                cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
+                cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
                     elaboratable.child(
                         trait_ref
                             .to_host_effect_clause(cx, data.constness)
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index aadb64f45d7..b01d3dc5269 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,12 +1,11 @@
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::fold::TypeFoldable;
-use crate::inherent::*;
 use crate::relate::RelateResult;
 use crate::relate::combine::PredicateEmittingRelation;
-use crate::solve::Reveal;
 use crate::{self as ty, Interner};
 
 /// The current typing mode of an inference context. We unfortunately have some
@@ -20,6 +19,7 @@ use crate::{self as ty, Interner};
 /// If neither of these functions are available, feel free to reach out to
 /// t-types for help.
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum TypingMode<I: Interner> {
     /// When checking whether impls overlap, we check whether any obligations
@@ -56,18 +56,6 @@ impl<I: Interner> TypingMode<I> {
     pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
         TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
     }
-
-    /// FIXME(#132279): Using this function is questionable as the `param_env`
-    /// does not track `defining_opaque_types` and whether we're in coherence mode.
-    /// Many uses of this function should also use a not-yet implemented typing mode
-    /// which reveals already defined opaque types in the future. This function will
-    /// get completely removed at some point.
-    pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode<I> {
-        match param_env.reveal() {
-            Reveal::UserFacing => TypingMode::non_body_analysis(),
-            Reveal::All => TypingMode::PostAnalysis,
-        }
-    }
 }
 
 pub trait InferCtxtLike: Sized {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 36ddddccfa2..93b9c2e2892 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -223,12 +223,13 @@ pub trait Interner:
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
 
-    fn is_const_impl(self, def_id: Self::DefId) -> bool;
+    fn impl_is_const(self, def_id: Self::DefId) -> bool;
+    fn fn_is_const(self, def_id: Self::DefId) -> bool;
     fn const_conditions(
         self,
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
-    fn implied_const_bounds(
+    fn explicit_implied_const_bounds(
         self,
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
@@ -277,8 +278,6 @@ pub trait Interner:
     fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
     fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
 
-    fn layout_is_pointer_like(self, param_env: Self::ParamEnv, ty: Self::Ty) -> bool;
-
     type UnsizingParams: Deref<Target = BitSet<u32>>;
     fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
 
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index d6ca22a90a4..df43346065d 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -31,7 +31,6 @@ pub enum TraitSolverLangItem {
     Metadata,
     Option,
     PointeeTrait,
-    PointerLike,
     Poll,
     Sized,
     TransmuteTrait,
diff --git a/config.example.toml b/config.example.toml
index 9dc71b10f70..d3233ad17b5 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -81,7 +81,7 @@
 # Indicates whether the LLVM plugin is enabled or not
 #plugins = false
 
-# Wheter to build Enzyme as AutoDiff backend.
+# Whether to build Enzyme as AutoDiff backend.
 #enzyme = false
 
 # Whether to build LLVM with support for it's gpu offload runtime.
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 70ecac4e17c..97996d5f0b2 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -158,9 +158,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.161"
+version = "0.2.162"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index bb6dd1d2d30..ee60ec0fbac 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -191,6 +191,8 @@ use core::error::{self, Error};
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
+#[cfg(not(bootstrap))]
+use core::marker::PointerLike;
 use core::marker::{Tuple, Unsize};
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
@@ -1500,6 +1502,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [`as_ptr`]: Self::as_ptr
     #[unstable(feature = "box_as_ptr", issue = "129090")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub fn as_mut_ptr(b: &mut Self) -> *mut T {
         // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
@@ -1548,6 +1551,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [`as_ptr`]: Self::as_ptr
     #[unstable(feature = "box_as_ptr", issue = "129090")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub fn as_ptr(b: &Self) -> *const T {
         // This is a primitive deref, not going through `DerefMut`, and therefore not materializing
@@ -2129,3 +2133,7 @@ impl<E: Error> Error for Box<E> {
         Error::provide(&**self, request);
     }
 }
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+impl<T> PointerLike for Box<T> {}
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 66353ccfa47..213924d1d02 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -677,7 +677,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         }
     }
 
-    /// Returns the key-value pair corresponding to the supplied key.
+    /// Returns the key-value pair corresponding to the supplied key. This is
+    /// potentially useful:
+    /// - for key types where non-identical keys can be considered equal;
+    /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or
+    /// - for getting a reference to a key with the same lifetime as the collection.
     ///
     /// The supplied key may be any borrowed form of the map's key type, but the ordering
     /// on the borrowed form *must* match the ordering on the key type.
@@ -685,12 +689,46 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// # Examples
     ///
     /// ```
+    /// use std::cmp::Ordering;
     /// use std::collections::BTreeMap;
     ///
+    /// #[derive(Clone, Copy, Debug)]
+    /// struct S {
+    ///     id: u32,
+    /// #   #[allow(unused)] // prevents a "field `name` is never read" error
+    ///     name: &'static str, // ignored by equality and ordering operations
+    /// }
+    ///
+    /// impl PartialEq for S {
+    ///     fn eq(&self, other: &S) -> bool {
+    ///         self.id == other.id
+    ///     }
+    /// }
+    ///
+    /// impl Eq for S {}
+    ///
+    /// impl PartialOrd for S {
+    ///     fn partial_cmp(&self, other: &S) -> Option<Ordering> {
+    ///         self.id.partial_cmp(&other.id)
+    ///     }
+    /// }
+    ///
+    /// impl Ord for S {
+    ///     fn cmp(&self, other: &S) -> Ordering {
+    ///         self.id.cmp(&other.id)
+    ///     }
+    /// }
+    ///
+    /// let j_a = S { id: 1, name: "Jessica" };
+    /// let j_b = S { id: 1, name: "Jess" };
+    /// let p = S { id: 2, name: "Paul" };
+    /// assert_eq!(j_a, j_b);
+    ///
     /// let mut map = BTreeMap::new();
-    /// map.insert(1, "a");
-    /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
-    /// assert_eq!(map.get_key_value(&2), None);
+    /// map.insert(j_a, "Paris");
+    /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris")));
+    /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case
+    /// assert_eq!(map.get_key_value(&p), None);
     /// ```
     #[stable(feature = "map_get_key_value", since = "1.40.0")]
     pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index 6922ea9b79b..d3dbd10c863 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -19,6 +19,40 @@ impl<'a, T> Iter<'a, T> {
     pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self {
         Self { i1, i2 }
     }
+
+    /// Views the underlying data as a pair of subslices of the original data.
+    ///
+    /// The slices contain, in order, the contents of the deque not yet yielded
+    /// by the iterator.
+    ///
+    /// This has the same lifetime as the original `VecDeque`, and so the
+    /// iterator can continue to be used while this exists.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_iter_as_slices)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque = VecDeque::new();
+    /// deque.push_back(0);
+    /// deque.push_back(1);
+    /// deque.push_back(2);
+    /// deque.push_front(10);
+    /// deque.push_front(9);
+    /// deque.push_front(8);
+    ///
+    /// let mut iter = deque.iter();
+    /// iter.next();
+    /// iter.next_back();
+    ///
+    /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..]));
+    /// ```
+    #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
+    pub fn as_slices(&self) -> (&'a [T], &'a [T]) {
+        (self.i1.as_slice(), self.i2.as_slice())
+    }
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 84b74109580..0c5f06e752b 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -19,6 +19,113 @@ impl<'a, T> IterMut<'a, T> {
     pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self {
         Self { i1, i2 }
     }
+
+    /// Views the underlying data as a pair of subslices of the original data.
+    ///
+    /// The slices contain, in order, the contents of the deque not yet yielded
+    /// by the iterator.
+    ///
+    /// To avoid creating `&mut` references that alias, this is forced to
+    /// consume the iterator.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_iter_as_slices)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque = VecDeque::new();
+    /// deque.push_back(0);
+    /// deque.push_back(1);
+    /// deque.push_back(2);
+    /// deque.push_front(10);
+    /// deque.push_front(9);
+    /// deque.push_front(8);
+    ///
+    /// let mut iter = deque.iter_mut();
+    /// iter.next();
+    /// iter.next_back();
+    ///
+    /// let slices = iter.into_slices();
+    /// slices.0[0] = 42;
+    /// slices.1[0] = 24;
+    /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..]));
+    /// ```
+    #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
+    pub fn into_slices(self) -> (&'a mut [T], &'a mut [T]) {
+        (self.i1.into_slice(), self.i2.into_slice())
+    }
+
+    /// Views the underlying data as a pair of subslices of the original data.
+    ///
+    /// The slices contain, in order, the contents of the deque not yet yielded
+    /// by the iterator.
+    ///
+    /// To avoid creating `&mut [T]` references that alias, the returned slices
+    /// borrow their lifetimes from the iterator the method is applied on.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_iter_as_slices)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque = VecDeque::new();
+    /// deque.push_back(0);
+    /// deque.push_back(1);
+    /// deque.push_back(2);
+    /// deque.push_front(10);
+    /// deque.push_front(9);
+    /// deque.push_front(8);
+    ///
+    /// let mut iter = deque.iter_mut();
+    /// iter.next();
+    /// iter.next_back();
+    ///
+    /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..]));
+    /// ```
+    #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
+    pub fn as_slices(&self) -> (&[T], &[T]) {
+        (self.i1.as_slice(), self.i2.as_slice())
+    }
+
+    /// Views the underlying data as a pair of subslices of the original data.
+    ///
+    /// The slices contain, in order, the contents of the deque not yet yielded
+    /// by the iterator.
+    ///
+    /// To avoid creating `&mut [T]` references that alias, the returned slices
+    /// borrow their lifetimes from the iterator the method is applied on.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_deque_iter_as_slices)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque = VecDeque::new();
+    /// deque.push_back(0);
+    /// deque.push_back(1);
+    /// deque.push_back(2);
+    /// deque.push_front(10);
+    /// deque.push_front(9);
+    /// deque.push_front(8);
+    ///
+    /// let mut iter = deque.iter_mut();
+    /// iter.next();
+    /// iter.next_back();
+    ///
+    /// iter.as_mut_slices().0[0] = 42;
+    /// iter.as_mut_slices().1[0] = 24;
+    /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..]));
+    /// ```
+    #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
+    pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
+        (self.i1.as_mut_slice(), self.i2.as_mut_slice())
+    }
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index dd9dfa3f5e2..041ff37897f 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -136,6 +136,7 @@
 #![feature(panic_internals)]
 #![feature(pattern)]
 #![feature(pin_coerce_unsized_trait)]
+#![feature(pointer_like_trait)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
@@ -143,6 +144,7 @@
 #![feature(sized_type_properties)]
 #![feature(slice_from_ptr_range)]
 #![feature(slice_index_methods)]
+#![feature(slice_iter_mut_as_mut_slice)]
 #![feature(slice_ptr_get)]
 #![feature(slice_range)]
 #![feature(std_internals)]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index b042720933b..e0576c25515 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -116,7 +116,7 @@ use crate::vec::Vec;
 /// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider
 /// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8
 /// is a variable width encoding, `String`s are typically smaller than an array of
-/// the same `chars`:
+/// the same `char`s:
 ///
 /// ```
 /// use std::mem;
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 07a1bd49321..990b7e8f761 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1662,6 +1662,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub const fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
@@ -1724,6 +1725,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 1a461987c76..bfd2a71f97b 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -587,6 +587,7 @@ impl<T: ?Sized> Cell<T> {
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
     #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn as_ptr(&self) -> *mut T {
         self.value.get()
@@ -1149,6 +1150,7 @@ impl<T: ?Sized> RefCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub fn as_ptr(&self) -> *mut T {
         self.value.get()
@@ -2158,6 +2160,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn get(&self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
@@ -2271,6 +2274,7 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T>
 /// See [`UnsafeCell`] for details.
 #[unstable(feature = "sync_unsafe_cell", issue = "95439")]
 #[repr(transparent)]
+#[rustc_diagnostic_item = "SyncUnsafeCell"]
 #[rustc_pub_transparent]
 pub struct SyncUnsafeCell<T: ?Sized> {
     value: UnsafeCell<T>,
@@ -2304,6 +2308,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> {
     /// when casting to `&mut T`, and ensure that there are no mutations
     /// or mutable aliases going on when casting to `&T`
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn get(&self) -> *mut T {
         self.value.get()
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 85571222b5c..9e32f74227c 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -500,6 +500,7 @@ impl CStr {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[rustc_never_returns_null_ptr]
     pub const fn as_ptr(&self) -> *const c_char {
         self.inner.as_ptr()
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 72e34e5faf5..e9859a58696 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -15,7 +15,7 @@
 //! and make the intrinsic declaration a `const fn`.
 //!
 //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
-//! `#[rustc_const_stable_intrinsic]` needs to be added to the intrinsic. Such a change requires
+//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires
 //! T-lang approval, because it may bake a feature into the language that cannot be replicated in
 //! user code without compiler support.
 //!
@@ -1435,7 +1435,7 @@ pub fn abort() -> ! {
     bootstrap,
     rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")
 )]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1454,7 +1454,7 @@ pub const unsafe fn unreachable() -> ! {
 ///
 /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`].
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
@@ -1465,6 +1465,22 @@ pub const unsafe fn assume(b: bool) {
     }
 }
 
+/// Hints to the compiler that current code path is cold.
+///
+/// Note that, unlike most intrinsics, this is safe to call;
+/// it does not require an `unsafe` block.
+/// Therefore, implementations must not require the user to uphold
+/// any safety invariants.
+///
+/// This intrinsic does not have a stable counterpart.
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+#[cfg(not(bootstrap))]
+#[rustc_nounwind]
+#[miri::intrinsic_fallback_is_spec]
+#[cold]
+pub const fn cold_path() {}
+
 /// Hints to the compiler that branch condition is likely to be true.
 /// Returns the value passed to it.
 ///
@@ -1480,13 +1496,21 @@ pub const unsafe fn assume(b: bool) {
     bootstrap,
     rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
 )]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_intrinsic]
 #[rustc_nounwind]
-#[miri::intrinsic_fallback_is_spec]
+#[inline(always)]
 pub const fn likely(b: bool) -> bool {
-    b
+    #[cfg(bootstrap)]
+    {
+        b
+    }
+    #[cfg(not(bootstrap))]
+    if b {
+        true
+    } else {
+        cold_path();
+        false
+    }
 }
 
 /// Hints to the compiler that branch condition is likely to be false.
@@ -1504,13 +1528,21 @@ pub const fn likely(b: bool) -> bool {
     bootstrap,
     rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
 )]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_intrinsic]
 #[rustc_nounwind]
-#[miri::intrinsic_fallback_is_spec]
+#[inline(always)]
 pub const fn unlikely(b: bool) -> bool {
-    b
+    #[cfg(bootstrap)]
+    {
+        b
+    }
+    #[cfg(not(bootstrap))]
+    if b {
+        cold_path();
+        true
+    } else {
+        false
+    }
 }
 
 /// Returns either `true_val` or `false_val` depending on condition `b` with a
@@ -1539,7 +1571,7 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1552,7 +1584,7 @@ pub const fn assert_inhabited<T>() {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1564,7 +1596,7 @@ pub const fn assert_zero_valid<T>() {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1581,7 +1613,7 @@ pub const fn assert_mem_uninitialized_valid<T>() {
 ///
 /// Consider using [`core::panic::Location::caller`] instead.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1599,7 +1631,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> {
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1913,7 +1945,7 @@ pub const unsafe fn transmute<Src, Dst>(_src: Src) -> Dst {
 /// This is not expected to ever be exposed directly to users, rather it
 /// may eventually be exposed through some more-constrained API.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1935,7 +1967,7 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(_src: Src) -> Dst {
 ///
 /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1961,7 +1993,7 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
 /// The stabilized version of this intrinsic is [`pointer::offset`].
 #[must_use = "returns a new pointer rather than modifying its argument"]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -1984,7 +2016,7 @@ pub const unsafe fn offset<Ptr, Delta>(_dst: Ptr, _offset: Delta) -> Ptr {
 /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`].
 #[must_use = "returns a new pointer rather than modifying its argument"]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2692,7 +2724,7 @@ pub fn frem_algebraic<T: Copy>(_a: T, _b: T) -> T {
 /// primitives via the `count_ones` method. For example,
 /// [`u32::count_ones`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2737,7 +2769,7 @@ pub const fn ctpop<T: Copy>(_x: T) -> u32 {
 /// assert_eq!(num_leading, 16);
 /// ```
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2763,7 +2795,7 @@ pub const fn ctlz<T: Copy>(_x: T) -> u32 {
 /// assert_eq!(num_leading, 3);
 /// ```
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2808,7 +2840,7 @@ pub const unsafe fn ctlz_nonzero<T: Copy>(_x: T) -> u32 {
 /// assert_eq!(num_trailing, 16);
 /// ```
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2834,7 +2866,7 @@ pub const fn cttz<T: Copy>(_x: T) -> u32 {
 /// assert_eq!(num_trailing, 3);
 /// ```
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2853,7 +2885,7 @@ pub const unsafe fn cttz_nonzero<T: Copy>(_x: T) -> u32 {
 /// primitives via the `swap_bytes` method. For example,
 /// [`u32::swap_bytes`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2872,7 +2904,7 @@ pub const fn bswap<T: Copy>(_x: T) -> T {
 /// primitives via the `reverse_bits` method. For example,
 /// [`u32::reverse_bits`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2905,7 +2937,7 @@ pub const fn three_way_compare<T: Copy>(_lhs: T, _rhss: T) -> crate::cmp::Orderi
 /// primitives via the `overflowing_add` method. For example,
 /// [`u32::overflowing_add`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2924,7 +2956,7 @@ pub const fn add_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
 /// primitives via the `overflowing_sub` method. For example,
 /// [`u32::overflowing_sub`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2943,7 +2975,7 @@ pub const fn sub_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
 /// primitives via the `overflowing_mul` method. For example,
 /// [`u32::overflowing_mul`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2970,7 +3002,7 @@ pub const unsafe fn exact_div<T: Copy>(_x: T, _y: T) -> T {
 /// primitives via the `checked_div` method. For example,
 /// [`u32::checked_div`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2984,7 +3016,7 @@ pub const unsafe fn unchecked_div<T: Copy>(_x: T, _y: T) -> T {
 /// primitives via the `checked_rem` method. For example,
 /// [`u32::checked_rem`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -2999,7 +3031,7 @@ pub const unsafe fn unchecked_rem<T: Copy>(_x: T, _y: T) -> T {
 /// primitives via the `checked_shl` method. For example,
 /// [`u32::checked_shl`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3013,7 +3045,7 @@ pub const unsafe fn unchecked_shl<T: Copy, U: Copy>(_x: T, _y: U) -> T {
 /// primitives via the `checked_shr` method. For example,
 /// [`u32::checked_shr`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3027,7 +3059,7 @@ pub const unsafe fn unchecked_shr<T: Copy, U: Copy>(_x: T, _y: U) -> T {
 /// The stable counterpart of this intrinsic is `unchecked_add` on the various
 /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`].
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3041,7 +3073,7 @@ pub const unsafe fn unchecked_add<T: Copy>(_x: T, _y: T) -> T {
 /// The stable counterpart of this intrinsic is `unchecked_sub` on the various
 /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`].
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3055,7 +3087,7 @@ pub const unsafe fn unchecked_sub<T: Copy>(_x: T, _y: T) -> T {
 /// The stable counterpart of this intrinsic is `unchecked_mul` on the various
 /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`].
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3074,7 +3106,7 @@ pub const unsafe fn unchecked_mul<T: Copy>(_x: T, _y: T) -> T {
 /// primitives via the `rotate_left` method. For example,
 /// [`u32::rotate_left`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3093,7 +3125,7 @@ pub const fn rotate_left<T: Copy>(_x: T, _shift: u32) -> T {
 /// primitives via the `rotate_right` method. For example,
 /// [`u32::rotate_right`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3112,7 +3144,7 @@ pub const fn rotate_right<T: Copy>(_x: T, _shift: u32) -> T {
 /// primitives via the `wrapping_add` method. For example,
 /// [`u32::wrapping_add`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3130,7 +3162,7 @@ pub const fn wrapping_add<T: Copy>(_a: T, _b: T) -> T {
 /// primitives via the `wrapping_sub` method. For example,
 /// [`u32::wrapping_sub`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3148,7 +3180,7 @@ pub const fn wrapping_sub<T: Copy>(_a: T, _b: T) -> T {
 /// primitives via the `wrapping_mul` method. For example,
 /// [`u32::wrapping_mul`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3167,7 +3199,7 @@ pub const fn wrapping_mul<T: Copy>(_a: T, _b: T) -> T {
 /// primitives via the `saturating_add` method. For example,
 /// [`u32::saturating_add`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3185,7 +3217,7 @@ pub const fn saturating_add<T: Copy>(_a: T, _b: T) -> T {
 /// primitives via the `saturating_sub` method. For example,
 /// [`u32::saturating_sub`]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3200,7 +3232,7 @@ pub const fn saturating_sub<T: Copy>(_a: T, _b: T) -> T {
 /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it
 /// trivially obeys runtime-MIR rules about derefs in operands.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3215,7 +3247,7 @@ pub const unsafe fn read_via_copy<T>(_ptr: *const T) -> T {
 /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so
 /// that it trivially obeys runtime-MIR rules about derefs in operands.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3233,7 +3265,7 @@ pub const unsafe fn write_via_move<T>(_ptr: *mut T, _value: T) {
 ///
 /// The stabilized version of this intrinsic is [`core::mem::discriminant`].
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3273,7 +3305,7 @@ extern "rust-intrinsic" {
 
 /// See documentation of `<*const T>::offset_from` for details.
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
@@ -3292,8 +3324,8 @@ pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T)
 
 /// See documentation of `<*const T>::guaranteed_eq` for details.
 /// Returns `2` if the result is unknown.
-/// Returns `1` if the pointers are guaranteed equal
-/// Returns `0` if the pointers are guaranteed inequal
+/// Returns `1` if the pointers are guaranteed equal.
+/// Returns `0` if the pointers are guaranteed inequal.
 #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))]
 #[rustc_intrinsic]
 #[rustc_nounwind]
@@ -3535,7 +3567,6 @@ pub(crate) macro const_eval_select {
 /// In other words, the following code has *Undefined Behavior*:
 ///
 /// ```no_run
-/// #![feature(is_val_statically_known)]
 /// #![feature(core_intrinsics)]
 /// # #![allow(internal_features)]
 /// use std::hint::unreachable_unchecked;
@@ -3548,7 +3579,6 @@ pub(crate) macro const_eval_select {
 /// may panic, or it may not:
 ///
 /// ```no_run
-/// #![feature(is_val_statically_known)]
 /// #![feature(core_intrinsics)]
 /// # #![allow(internal_features)]
 /// use std::intrinsics::is_val_statically_known;
@@ -3581,7 +3611,6 @@ pub(crate) macro const_eval_select {
 /// behave identically:
 ///
 /// ```
-/// #![feature(is_val_statically_known)]
 /// #![feature(core_intrinsics)]
 /// # #![allow(internal_features)]
 /// use std::intrinsics::is_val_statically_known;
@@ -3598,7 +3627,11 @@ pub(crate) macro const_eval_select {
 /// # _ = foo(&5_i32);
 /// # _ = bar(&5_i32);
 /// ```
-#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
+#[cfg_attr(
+    bootstrap,
+    rustc_const_stable(feature = "const_is_val_statically_known", since = "CURRENT_RUSTC_VERSION")
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
@@ -3641,7 +3674,7 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
 /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
 /// primarily used by [`ub_checks::assert_unsafe_precondition`].
 #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] // just for UB checks
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)] // just for UB checks
 #[inline(always)]
 #[rustc_intrinsic]
 pub const fn ub_checks() -> bool {
@@ -3725,7 +3758,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn size_of<T>() -> usize {
@@ -3743,7 +3776,7 @@ pub const fn size_of<T>() -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn min_align_of<T>() -> usize {
@@ -3857,7 +3890,7 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
@@ -3886,7 +3919,7 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
     bootstrap,
     cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))
 )]
-#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+#[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
@@ -3993,7 +4026,7 @@ pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *cons
 #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))]
-    #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+    #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
     #[rustc_nounwind]
     #[rustc_intrinsic]
     #[rustc_intrinsic_must_be_overridden]
@@ -4013,9 +4046,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
             count: usize = count,
         ) => {
             let zero_size = count == 0 || size == 0;
-            ub_checks::is_aligned_and_not_null(src, align, zero_size)
-                && ub_checks::is_aligned_and_not_null(dst, align, zero_size)
-                && ub_checks::is_nonoverlapping(src, dst, size, count)
+            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
+                && ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
         }
     );
 
@@ -4100,7 +4133,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
 #[rustc_diagnostic_item = "ptr_copy"]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))]
-    #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+    #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
     #[rustc_nounwind]
     #[rustc_intrinsic]
     #[rustc_intrinsic_must_be_overridden]
@@ -4119,8 +4152,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
                 align: usize = align_of::<T>(),
                 zero_size: bool = T::IS_ZST || count == 0,
             ) =>
-            ub_checks::is_aligned_and_not_null(src, align, zero_size)
-                && ub_checks::is_aligned_and_not_null(dst, align, zero_size)
+            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
         );
         copy(src, dst, count)
     }
@@ -4184,7 +4217,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
 #[rustc_diagnostic_item = "ptr_write_bytes"]
 pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
     #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
-    #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)]
+    #[cfg_attr(not(bootstrap), rustc_intrinsic_const_stable_indirect)]
     #[rustc_nounwind]
     #[rustc_intrinsic]
     #[rustc_intrinsic_must_be_overridden]
@@ -4201,7 +4234,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
                 zero_size: bool = T::IS_ZST || count == 0,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, zero_size)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
         );
         write_bytes(dst, val, count)
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 6f7ea769420..d30bf96cfd4 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -109,6 +109,7 @@
 // tidy-alphabetical-start
 #![cfg_attr(bootstrap, feature(const_exact_div))]
 #![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
+#![cfg_attr(bootstrap, feature(const_ub_checks))]
 #![feature(array_ptr_get)]
 #![feature(asm_experimental_arch)]
 #![feature(const_align_of_val)]
@@ -120,8 +121,6 @@
 #![feature(const_float_methods)]
 #![feature(const_heap)]
 #![feature(const_nonnull_new)]
-#![feature(const_pin_2)]
-#![feature(const_ptr_is_null)]
 #![feature(const_ptr_sub_ptr)]
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_size_of_val)]
@@ -132,14 +131,12 @@
 #![feature(const_type_id)]
 #![feature(const_type_name)]
 #![feature(const_typed_swap)]
-#![feature(const_ub_checks)]
 #![feature(core_intrinsics)]
 #![feature(coverage_attribute)]
 #![feature(do_not_recommend)]
 #![feature(internal_impls_macro)]
 #![feature(ip)]
 #![feature(is_ascii_octdigit)]
-#![feature(is_val_statically_known)]
 #![feature(lazy_get)]
 #![feature(link_cfg)]
 #![feature(non_null_from_ref)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1c5c58d64a2..c8ea52a1fb0 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -981,6 +981,18 @@ pub trait Tuple {}
 )]
 pub trait PointerLike {}
 
+#[cfg(not(bootstrap))]
+marker_impls! {
+    #[unstable(feature = "pointer_like_trait", issue = "none")]
+    PointerLike for
+        usize,
+        {T} &T,
+        {T} &mut T,
+        {T} *const T,
+        {T} *mut T,
+        {T: PointerLike} crate::pin::Pin<T>,
+}
+
 /// A marker for types which can be used as types of `const` generic parameters.
 ///
 /// These types must have a proper equivalence relation (`Eq`) and it must be automatically
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 8c6cdf57c58..58315cb74f0 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -525,6 +525,7 @@ impl<T> MaybeUninit<T> {
     /// until they are, it is advisable to avoid them.)
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     pub const fn as_ptr(&self) -> *const T {
         // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
@@ -566,6 +567,7 @@ impl<T> MaybeUninit<T> {
     /// until they are, it is advisable to avoid them.)
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
         // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 4d24b102096..318bb8ee4cd 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2242,7 +2242,6 @@ macro_rules! int_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known)]
         pub const fn wrapping_pow(self, mut exp: u32) -> Self {
             if exp == 0 {
                 return 1;
@@ -2808,7 +2807,6 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         #[rustc_inherit_overflow_checks]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known)]
         pub const fn pow(self, mut exp: u32) -> Self {
             if exp == 0 {
                 return 1;
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 0a5101884f7..0383c13fa08 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2251,7 +2251,6 @@ macro_rules! uint_impl {
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known)]
         pub const fn wrapping_pow(self, mut exp: u32) -> Self {
             if exp == 0 {
                 return 1;
@@ -2791,7 +2790,6 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         #[rustc_inherit_overflow_checks]
-        #[rustc_allow_const_fn_unstable(is_val_statically_known)]
         pub const fn pow(self, mut exp: u32) -> Self {
             if exp == 0 {
                 return 1;
diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs
index e702056f00a..179aadf0c28 100644
--- a/library/core/src/panic.rs
+++ b/library/core/src/panic.rs
@@ -215,7 +215,7 @@ pub macro const_panic {
                 #[noinline]
                 if const #[track_caller] #[inline] { // Inline this, to prevent codegen
                     $crate::panic!($const_msg)
-                } else #[track_caller] { // Do not inline this, it makes perf worse
+                } else #[track_caller] #[cfg_attr(bootstrap, inline)] { // Do not inline this, it makes perf worse
                     $crate::panic!($runtime_msg)
                 }
             )
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 254b306fcaa..c14c49a0d92 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1214,7 +1214,8 @@ impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> {
     /// assert_eq!(*r, 5);
     /// ```
     #[inline(always)]
-    #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pin_into_inner", since = "1.39.0")]
     pub const fn into_inner(pin: Pin<Ptr>) -> Ptr {
         pin.__pointer
@@ -1503,7 +1504,8 @@ impl<Ptr: Deref> Pin<Ptr> {
     /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
     /// instead.
     #[inline(always)]
-    #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pin_into_inner", since = "1.39.0")]
     pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr {
         pin.__pointer
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 2d7507e2d53..0dbe819acb1 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -29,16 +29,18 @@ impl<T: ?Sized> *const T {
     /// assert!(!ptr.is_null());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_diagnostic_item = "ptr_const_is_null"]
     #[inline]
+    #[rustc_allow_const_fn_unstable(const_eval_select)]
     pub const fn is_null(self) -> bool {
         // Compare via a cast to a thin pointer, so fat pointers are only
         // considering their "data" part for null-ness.
         let ptr = self as *const u8;
         const_eval_select!(
             @capture { ptr: *const u8 } -> bool:
-            if const #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] {
+            // This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang.
+            if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] {
                 match (ptr).guaranteed_eq(null_mut()) {
                     Some(res) => res,
                     // To remain maximally convervative, we stop execution when we don't
@@ -280,7 +282,7 @@ impl<T: ?Sized> *const T {
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         // SAFETY: the caller must guarantee that `self` is valid
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 603e9044217..805edddfe63 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1103,9 +1103,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             count: usize = count,
         ) => {
             let zero_size = size == 0 || count == 0;
-            ub_checks::is_aligned_and_not_null(x, align, zero_size)
-                && ub_checks::is_aligned_and_not_null(y, align, zero_size)
-                && ub_checks::is_nonoverlapping(x, y, size, count)
+            ub_checks::maybe_is_aligned_and_not_null(x, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(y, align, zero_size)
+                && ub_checks::maybe_is_nonoverlapping(x, y, size, count)
         }
     );
 
@@ -1216,7 +1216,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         mem::replace(&mut *dst, src)
     }
@@ -1369,7 +1369,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         crate::intrinsics::read_via_copy(src)
     }
@@ -1573,7 +1573,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         intrinsics::write_via_move(dst, src)
     }
@@ -1745,7 +1745,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         intrinsics::volatile_load(src)
     }
@@ -1825,7 +1825,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
                 is_zst: bool = T::IS_ZST,
-            ) => ub_checks::is_aligned_and_not_null(addr, align, is_zst)
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
         );
         intrinsics::volatile_store(dst, src);
     }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 344ba46a50e..f0204bd0f77 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -29,7 +29,7 @@ impl<T: ?Sized> *mut T {
     /// assert!(!ptr.is_null());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_diagnostic_item = "ptr_is_null"]
     #[inline]
     pub const fn is_null(self) -> bool {
@@ -271,7 +271,7 @@ impl<T: ?Sized> *mut T {
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         // SAFETY: the caller must guarantee that `self` is valid for a
@@ -619,7 +619,7 @@ impl<T: ?Sized> *mut T {
     /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
-    #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+    #[rustc_const_stable(feature = "const_ptr_is_null", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
         // SAFETY: the caller must guarantee that `self` is be valid for
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index ef52cc44126..c855f963771 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -735,6 +735,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_ptr(&self) -> *const T {
@@ -765,6 +766,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 89840881c4d..319b76899bf 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -132,7 +132,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-            ub_checks::is_aligned_and_not_null(data, align, false)
+            ub_checks::maybe_is_aligned_and_not_null(data, align, false)
                 && ub_checks::is_valid_allocation_size(size, len)
         );
         &*ptr::slice_from_raw_parts(data, len)
@@ -186,7 +186,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-            ub_checks::is_aligned_and_not_null(data, align, false)
+            ub_checks::maybe_is_aligned_and_not_null(data, align, false)
                 && ub_checks::is_valid_allocation_size(size, len)
         );
         &mut *ptr::slice_from_raw_parts_mut(data, len)
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 5aecbf303f9..4629b770cb4 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -373,6 +373,7 @@ impl str {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_ptr(&self) -> *const u8 {
@@ -390,6 +391,7 @@ impl str {
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")]
     #[rustc_never_returns_null_ptr]
+    #[cfg_attr(not(bootstrap), rustc_as_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_mut_ptr(&mut self) -> *mut u8 {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 93b4ad5c1c9..7f2a5424787 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -469,7 +469,7 @@ impl AtomicBool {
     /// [valid]: crate::ptr#safety
     /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
     #[stable(feature = "atomic_from_ptr", since = "1.75.0")]
-    #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
+    #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
         // SAFETY: guaranteed by the caller
         unsafe { &*ptr.cast() }
@@ -1264,7 +1264,7 @@ impl<T> AtomicPtr<T> {
     /// [valid]: crate::ptr#safety
     /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
     #[stable(feature = "atomic_from_ptr", since = "1.75.0")]
-    #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
+    #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
         // SAFETY: guaranteed by the caller
         unsafe { &*ptr.cast() }
@@ -2263,7 +2263,7 @@ macro_rules! atomic_int {
             /// [valid]: crate::ptr#safety
             /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
             #[stable(feature = "atomic_from_ptr", since = "1.75.0")]
-            #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
+            #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
             pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
                 // SAFETY: guaranteed by the caller
                 unsafe { &*ptr.cast() }
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index 8fcbda141da..3e6110c9c88 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -64,8 +64,6 @@ macro_rules! assert_unsafe_precondition {
             #[rustc_no_mir_inline]
             #[inline]
             #[rustc_nounwind]
-            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
-            #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
             const fn precondition_check($($name:$ty),*) {
                 if !$e {
                     ::core::panicking::panic_nounwind(
@@ -116,12 +114,16 @@ pub(crate) const fn check_language_ub() -> bool {
 /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
 /// check is anyway not executed in `const`.
 #[inline]
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
-pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+pub(crate) const fn maybe_is_aligned_and_not_null(
+    ptr: *const (),
+    align: usize,
+    is_zst: bool,
+) -> 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:
-        if const #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] {
+        if const {
             is_zst || !ptr.is_null()
         } else {
             ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
@@ -141,8 +143,8 @@ pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
 /// Note that in const-eval this function just returns `true` and therefore must
 /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
 #[inline]
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
-pub(crate) const fn is_nonoverlapping(
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+pub(crate) const fn maybe_is_nonoverlapping(
     src: *const (),
     dst: *const (),
     size: usize,
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index f515e9e4109..f7825571cd7 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -21,7 +21,6 @@
 #![feature(const_eval_select)]
 #![feature(const_heap)]
 #![feature(const_nonnull_new)]
-#![feature(const_pin_2)]
 #![feature(const_trait_impl)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index b732fdf1696..c1ab70b714a 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -34,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.161", default-features = false, features = [
+libc = { version = "0.2.162", default-features = false, features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index ded4f404d78..24bbc2f32cf 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -880,7 +880,11 @@ where
         self.base.get(k)
     }
 
-    /// Returns the key-value pair corresponding to the supplied key.
+    /// Returns the key-value pair corresponding to the supplied key. This is
+    /// potentially useful:
+    /// - for key types where non-identical keys can be considered equal;
+    /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or
+    /// - for getting a reference to a key with the same lifetime as the collection.
     ///
     /// The supplied key may be any borrowed form of the map's key type, but
     /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
@@ -890,11 +894,39 @@ where
     ///
     /// ```
     /// use std::collections::HashMap;
+    /// use std::hash::{Hash, Hasher};
+    ///
+    /// #[derive(Clone, Copy, Debug)]
+    /// struct S {
+    ///     id: u32,
+    /// #   #[allow(unused)] // prevents a "field `name` is never read" error
+    ///     name: &'static str, // ignored by equality and hashing operations
+    /// }
+    ///
+    /// impl PartialEq for S {
+    ///     fn eq(&self, other: &S) -> bool {
+    ///         self.id == other.id
+    ///     }
+    /// }
+    ///
+    /// impl Eq for S {}
+    ///
+    /// impl Hash for S {
+    ///     fn hash<H: Hasher>(&self, state: &mut H) {
+    ///         self.id.hash(state);
+    ///     }
+    /// }
+    ///
+    /// let j_a = S { id: 1, name: "Jessica" };
+    /// let j_b = S { id: 1, name: "Jess" };
+    /// let p = S { id: 2, name: "Paul" };
+    /// assert_eq!(j_a, j_b);
     ///
     /// let mut map = HashMap::new();
-    /// map.insert(1, "a");
-    /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
-    /// assert_eq!(map.get_key_value(&2), None);
+    /// map.insert(j_a, "Paris");
+    /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris")));
+    /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case
+    /// assert_eq!(map.get_key_value(&p), None);
     /// ```
     #[inline]
     #[stable(feature = "map_get_key_value", since = "1.40.0")]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 76fdb1a4ffd..555e8804eab 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2738,6 +2738,10 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 
 /// Removes an empty directory.
 ///
+/// If you want to remove a directory that is not empty, as well as all
+/// of its contents recursively, consider using [`remove_dir_all`]
+/// instead.
+///
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `rmdir` function on Unix
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 9f913eae095..fbfdb4fa023 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -153,7 +153,8 @@ impl<T> Cursor<T> {
     /// let reference = buff.get_mut();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut T {
+    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    pub const fn get_mut(&mut self) -> &mut T {
         &mut self.inner
     }
 
@@ -200,7 +201,8 @@ impl<T> Cursor<T> {
     /// assert_eq!(buff.position(), 4);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn set_position(&mut self, pos: u64) {
+    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    pub const fn set_position(&mut self, pos: u64) {
         self.pos = pos;
     }
 }
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 30d43c8bbfd..4302e24781e 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1448,6 +1448,9 @@ mod self_upper_keyword {}
 /// in a multithreaded context. As such, all accesses to mutable `static`s
 /// require an [`unsafe`] block.
 ///
+/// When possible, it's often better to use a non-mutable `static` with an
+/// interior mutable type such as [`Mutex`], [`OnceLock`], or an [atomic].
+///
 /// Despite their unsafety, mutable `static`s are necessary in many contexts:
 /// they can be used to represent global state shared by the whole program or in
 /// [`extern`] blocks to bind to variables from C libraries.
@@ -1468,7 +1471,10 @@ mod self_upper_keyword {}
 /// [`extern`]: keyword.extern.html
 /// [`mut`]: keyword.mut.html
 /// [`unsafe`]: keyword.unsafe.html
+/// [`Mutex`]: sync::Mutex
+/// [`OnceLock`]: sync::OnceLock
 /// [`RefCell`]: cell::RefCell
+/// [atomic]: sync::atomic
 /// [Reference]: ../reference/items/static-items.html
 mod static_keyword {}
 
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index da2da6f9dfc..d55d1c80dca 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -4,10 +4,10 @@ mod tests;
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::marker::PhantomData;
-use crate::mem::ManuallyDrop;
+use crate::mem::{ManuallyDrop, forget};
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
-use crate::sync::{LockResult, TryLockError, TryLockResult, poison};
+use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
 use crate::sys::sync as sys;
 
 /// A reader-writer lock
@@ -574,8 +574,12 @@ impl<T> From<T> for RwLock<T> {
 
 impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
     /// Creates a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`.
-    // SAFETY: if and only if `lock.inner.read()` (or `lock.inner.try_read()`) has been
-    // successfully called from the same thread before instantiating this object.
+    ///
+    /// # Safety
+    ///
+    /// This function is safe if and only if the same thread has successfully and safely called
+    /// `lock.inner.read()`, `lock.inner.try_read()`, or `lock.inner.downgrade()` before
+    /// instantiating this object.
     unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
         poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard {
             data: unsafe { NonNull::new_unchecked(lock.data.get()) },
@@ -957,6 +961,68 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
             None => Err(orig),
         }
     }
+
+    /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`].
+    ///
+    /// This method will atomically change the state of the [`RwLock`] from exclusive mode into
+    /// shared mode. This means that it is impossible for a writing thread to get in between a
+    /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the
+    /// [`RwLock`] in write mode.
+    ///
+    /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already
+    /// locked for writing, so this method cannot fail.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(rwlock_downgrade)]
+    /// use std::sync::{Arc, RwLock, RwLockWriteGuard};
+    ///
+    /// // The inner value starts as 0.
+    /// let rw = Arc::new(RwLock::new(0));
+    ///
+    /// // Put the lock in write mode.
+    /// let mut main_write_guard = rw.write().unwrap();
+    ///
+    /// let evil = rw.clone();
+    /// let handle = std::thread::spawn(move || {
+    ///     // This will not return until the main thread drops the `main_read_guard`.
+    ///     let mut evil_guard = evil.write().unwrap();
+    ///
+    ///     assert_eq!(*evil_guard, 1);
+    ///     *evil_guard = 2;
+    /// });
+    ///
+    /// // After spawning the writer thread, set the inner value to 1.
+    /// *main_write_guard = 1;
+    ///
+    /// // Atomically downgrade the write guard into a read guard.
+    /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard);
+    ///
+    /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2.
+    /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic");
+    ///
+    /// // Clean up everything now
+    /// drop(main_read_guard);
+    /// handle.join().unwrap();
+    ///
+    /// let final_check = rw.read().unwrap();
+    /// assert_eq!(*final_check, 2);
+    /// ```
+    #[unstable(feature = "rwlock_downgrade", issue = "128203")]
+    pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> {
+        let lock = s.lock;
+
+        // We don't want to call the destructor since that calls `write_unlock`.
+        forget(s);
+
+        // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write
+        // mode, satisfying the `downgrade` contract.
+        unsafe { lock.inner.downgrade() };
+
+        // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract.
+        unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) }
+    }
 }
 
 impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> {
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index 37a2e41641a..29cad4400f1 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -501,3 +501,111 @@ fn panic_while_mapping_write_unlocked_poison() {
 
     drop(lock);
 }
+
+#[test]
+fn test_downgrade_basic() {
+    let r = RwLock::new(());
+
+    let write_guard = r.write().unwrap();
+    let _read_guard = RwLockWriteGuard::downgrade(write_guard);
+}
+
+#[test]
+fn test_downgrade_observe() {
+    // Taken from the test `test_rwlock_downgrade` from:
+    // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
+
+    const W: usize = 20;
+    const N: usize = 100;
+
+    // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring
+    // that the value they wrote has not changed after downgrading.
+
+    let rw = Arc::new(RwLock::new(0));
+
+    // Spawn the writers that will do `W * N` operations and checks.
+    let handles: Vec<_> = (0..W)
+        .map(|_| {
+            let rw = rw.clone();
+            thread::spawn(move || {
+                for _ in 0..N {
+                    // Increment the counter.
+                    let mut write_guard = rw.write().unwrap();
+                    *write_guard += 1;
+                    let cur_val = *write_guard;
+
+                    // Downgrade the lock to read mode, where the value protected cannot be modified.
+                    let read_guard = RwLockWriteGuard::downgrade(write_guard);
+                    assert_eq!(cur_val, *read_guard);
+                }
+            })
+        })
+        .collect();
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+
+    assert_eq!(*rw.read().unwrap(), W * N);
+}
+
+#[test]
+// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
+// See <https://github.com/rust-lang/rust/issues/121950> for details.
+#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+fn test_downgrade_atomic() {
+    const NEW_VALUE: i32 = -1;
+
+    // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been
+    // downgraded, the lock must be in read mode and no other threads can take the write lock to
+    // modify the protected value.
+
+    // `W` is the number of evil writer threads.
+    const W: usize = 20;
+    let rwlock = Arc::new(RwLock::new(0));
+
+    // Spawns many evil writer threads that will try and write to the locked value before the
+    // initial writer (who has the exclusive lock) can read after it downgrades.
+    // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote
+    // itself as no other thread should be able to mutate the protected value.
+
+    // Put the lock in write mode, causing all future threads trying to access this go to sleep.
+    let mut main_write_guard = rwlock.write().unwrap();
+
+    // Spawn all of the evil writer threads. They will each increment the protected value by 1.
+    let handles: Vec<_> = (0..W)
+        .map(|_| {
+            let rwlock = rwlock.clone();
+            thread::spawn(move || {
+                // Will go to sleep since the main thread initially has the write lock.
+                let mut evil_guard = rwlock.write().unwrap();
+                *evil_guard += 1;
+            })
+        })
+        .collect();
+
+    // Wait for a good amount of time so that evil threads go to sleep.
+    // Note: this is not strictly necessary...
+    let eternity = crate::time::Duration::from_millis(42);
+    thread::sleep(eternity);
+
+    // Once everyone is asleep, set the value to `NEW_VALUE`.
+    *main_write_guard = NEW_VALUE;
+
+    // Atomically downgrade the write guard into a read guard.
+    let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard);
+
+    // If the above is not atomic, then it would be possible for an evil thread to get in front of
+    // this read and change the value to be non-negative.
+    assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic");
+
+    // Drop the main read guard and allow the evil writer threads to start incrementing.
+    drop(main_read_guard);
+
+    for handle in handles {
+        handle.join().unwrap();
+    }
+
+    let final_check = rwlock.read().unwrap();
+    assert_eq!(*final_check, W as i32 + NEW_VALUE);
+}
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index 0cc9cecb89d..1b83f4b0aee 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -18,6 +18,7 @@ use crate::{fmt, io};
 #[derive(Debug)]
 pub struct Command {
     prog: OsString,
+    args: Vec<OsString>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
 }
@@ -39,12 +40,11 @@ pub enum Stdio {
 
 impl Command {
     pub fn new(program: &OsStr) -> Command {
-        Command { prog: program.to_os_string(), stdout: None, stderr: None }
+        Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None }
     }
 
-    // FIXME: Implement arguments as reverse of parsing algorithm
-    pub fn arg(&mut self, _arg: &OsStr) {
-        panic!("unsupported")
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.to_os_string());
     }
 
     pub fn env_mut(&mut self) -> &mut CommandEnv {
@@ -72,7 +72,7 @@ impl Command {
     }
 
     pub fn get_args(&self) -> CommandArgs<'_> {
-        panic!("unsupported")
+        CommandArgs { iter: self.args.iter() }
     }
 
     pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -116,6 +116,12 @@ impl Command {
     pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
         let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
 
+        // UEFI adds the bin name by default
+        if !self.args.is_empty() {
+            let args = uefi_command_internal::create_args(&self.prog, &self.args);
+            cmd.set_args(args);
+        }
+
         // Setup Stdout
         let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
         let stdout = Self::create_pipe(stdout)?;
@@ -315,7 +321,7 @@ mod uefi_command_internal {
         stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
         stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
         st: OwnedTable<r_efi::efi::SystemTable>,
-        args: Option<Vec<u16>>,
+        args: Option<(*mut u16, usize)>,
     }
 
     impl Image {
@@ -449,20 +455,20 @@ mod uefi_command_internal {
             }
         }
 
-        pub fn set_args(&mut self, args: &OsStr) {
+        pub fn set_args(&mut self, args: Box<[u16]>) {
             let loaded_image: NonNull<loaded_image::Protocol> =
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
-            let mut args = args.encode_wide().collect::<Vec<u16>>();
-            let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
+            let len = args.len();
+            let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
+            let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
-                (*loaded_image.as_ptr()).load_options =
-                    args.as_mut_ptr() as *mut crate::ffi::c_void;
+                (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void;
                 (*loaded_image.as_ptr()).load_options_size = args_size;
             }
 
-            self.args = Some(args);
+            self.args = Some((ptr, len));
         }
 
         fn update_st_crc32(&mut self) -> io::Result<()> {
@@ -502,6 +508,10 @@ mod uefi_command_internal {
                     ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
                 }
             }
+
+            if let Some((ptr, len)) = self.args {
+                let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) };
+            }
         }
     }
 
@@ -681,4 +691,38 @@ mod uefi_command_internal {
             }
         }
     }
+
+    pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
+        const QUOTE: u16 = 0x0022;
+        const SPACE: u16 = 0x0020;
+        const CARET: u16 = 0x005e;
+        const NULL: u16 = 0;
+
+        // This is the lower bound on the final length under the assumption that
+        // the arguments only contain ASCII characters.
+        let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum());
+
+        // Wrap program name in quotes to avoid any problems
+        res.push(QUOTE);
+        res.extend(prog.encode_wide());
+        res.push(QUOTE);
+        res.push(SPACE);
+
+        for arg in args {
+            // Wrap the argument in quotes to be treat as single arg
+            res.push(QUOTE);
+            for c in arg.encode_wide() {
+                // CARET in quotes is used to escape CARET or QUOTE
+                if c == QUOTE || c == CARET {
+                    res.push(CARET);
+                }
+                res.push(c);
+            }
+            res.push(QUOTE);
+
+            res.push(SPACE);
+        }
+
+        res.into_boxed_slice()
+    }
 }
diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs
index 447048edf76..961819cae8d 100644
--- a/library/std/src/sys/sync/rwlock/futex.rs
+++ b/library/std/src/sys/sync/rwlock/futex.rs
@@ -18,6 +18,7 @@ pub struct RwLock {
 const READ_LOCKED: Primitive = 1;
 const MASK: Primitive = (1 << 30) - 1;
 const WRITE_LOCKED: Primitive = MASK;
+const DOWNGRADE: Primitive = READ_LOCKED.wrapping_sub(WRITE_LOCKED); // READ_LOCKED - WRITE_LOCKED
 const MAX_READERS: Primitive = MASK - 1;
 const READERS_WAITING: Primitive = 1 << 30;
 const WRITERS_WAITING: Primitive = 1 << 31;
@@ -54,6 +55,24 @@ fn is_read_lockable(state: Primitive) -> bool {
 }
 
 #[inline]
+fn is_read_lockable_after_wakeup(state: Primitive) -> bool {
+    // We make a special case for checking if we can read-lock _after_ a reader thread that went to
+    // sleep has been woken up by a call to `downgrade`.
+    //
+    // `downgrade` will wake up all readers and place the lock in read mode. Thus, there should be
+    // no readers waiting and the lock should be read-locked (not write-locked or unlocked).
+    //
+    // Note that we do not check if any writers are waiting. This is because a call to `downgrade`
+    // implies that the caller wants other readers to read the value protected by the lock. If we
+    // did not allow readers to acquire the lock before writers after a `downgrade`, then only the
+    // original writer would be able to read the value, thus defeating the purpose of `downgrade`.
+    state & MASK < MAX_READERS
+        && !has_readers_waiting(state)
+        && !is_write_locked(state)
+        && !is_unlocked(state)
+}
+
+#[inline]
 fn has_reached_max_readers(state: Primitive) -> bool {
     state & MASK == MAX_READERS
 }
@@ -84,6 +103,9 @@ impl RwLock {
         }
     }
 
+    /// # Safety
+    ///
+    /// The `RwLock` must be read-locked (N readers) in order to call this.
     #[inline]
     pub unsafe fn read_unlock(&self) {
         let state = self.state.fetch_sub(READ_LOCKED, Release) - READ_LOCKED;
@@ -100,11 +122,13 @@ impl RwLock {
 
     #[cold]
     fn read_contended(&self) {
+        let mut has_slept = false;
         let mut state = self.spin_read();
 
         loop {
-            // If we can lock it, lock it.
-            if is_read_lockable(state) {
+            // If we have just been woken up, first check for a `downgrade` call.
+            // Otherwise, if we can read-lock it, lock it.
+            if (has_slept && is_read_lockable_after_wakeup(state)) || is_read_lockable(state) {
                 match self.state.compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
                 {
                     Ok(_) => return, // Locked!
@@ -116,9 +140,7 @@ impl RwLock {
             }
 
             // Check for overflow.
-            if has_reached_max_readers(state) {
-                panic!("too many active read locks on RwLock");
-            }
+            assert!(!has_reached_max_readers(state), "too many active read locks on RwLock");
 
             // Make sure the readers waiting bit is set before we go to sleep.
             if !has_readers_waiting(state) {
@@ -132,6 +154,7 @@ impl RwLock {
 
             // Wait for the state to change.
             futex_wait(&self.state, state | READERS_WAITING, None);
+            has_slept = true;
 
             // Spin again after waking up.
             state = self.spin_read();
@@ -152,6 +175,9 @@ impl RwLock {
         }
     }
 
+    /// # Safety
+    ///
+    /// The `RwLock` must be write-locked (single writer) in order to call this.
     #[inline]
     pub unsafe fn write_unlock(&self) {
         let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED;
@@ -163,6 +189,22 @@ impl RwLock {
         }
     }
 
+    /// # Safety
+    ///
+    /// The `RwLock` must be write-locked (single writer) in order to call this.
+    #[inline]
+    pub unsafe fn downgrade(&self) {
+        // Removes all write bits and adds a single read bit.
+        let state = self.state.fetch_add(DOWNGRADE, Release);
+        debug_assert!(is_write_locked(state), "RwLock must be write locked to call `downgrade`");
+
+        if has_readers_waiting(state) {
+            // Since we had the exclusive lock, nobody else can unset this bit.
+            self.state.fetch_sub(READERS_WAITING, Relaxed);
+            futex_wake_all(&self.state);
+        }
+    }
+
     #[cold]
     fn write_contended(&self) {
         let mut state = self.spin_write();
diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs
index 6965e2e2cab..c11e59f719e 100644
--- a/library/std/src/sys/sync/rwlock/no_threads.rs
+++ b/library/std/src/sys/sync/rwlock/no_threads.rs
@@ -62,4 +62,9 @@ impl RwLock {
     pub unsafe fn write_unlock(&self) {
         assert_eq!(self.mode.replace(0), -1);
     }
+
+    #[inline]
+    pub unsafe fn downgrade(&self) {
+        assert_eq!(self.mode.replace(1), -1);
+    }
 }
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index 889961915f4..51330f8fafe 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -1,37 +1,38 @@
 //! Efficient read-write locking without `pthread_rwlock_t`.
 //!
-//! The readers-writer lock provided by the `pthread` library has a number of
-//! problems which make it a suboptimal choice for `std`:
+//! The readers-writer lock provided by the `pthread` library has a number of problems which make it
+//! a suboptimal choice for `std`:
 //!
-//! * It is non-movable, so it needs to be allocated (lazily, to make the
-//! constructor `const`).
-//! * `pthread` is an external library, meaning the fast path of acquiring an
-//! uncontended lock cannot be inlined.
-//! * Some platforms (at least glibc before version 2.25) have buggy implementations
-//! that can easily lead to undefined behavior in safe Rust code when not properly
-//! guarded against.
+//! * It is non-movable, so it needs to be allocated (lazily, to make the constructor `const`).
+//! * `pthread` is an external library, meaning the fast path of acquiring an uncontended lock
+//! cannot be inlined.
+//! * Some platforms (at least glibc before version 2.25) have buggy implementations that can easily
+//! lead to undefined behaviour in safe Rust code when not properly guarded against.
 //! * On some platforms (e.g. macOS), the lock is very slow.
 //!
-//! Therefore, we implement our own `RwLock`! Naively, one might reach for a
-//! spinlock, but those [can be quite problematic] when the lock is contended.
-//! Instead, this readers-writer lock copies its implementation strategy from
-//! the Windows [SRWLOCK] and the [usync] library. Spinning is still used for the
-//! fast path, but it is bounded: after spinning fails, threads will locklessly
-//! add an information structure containing a [`Thread`] handle into a queue of
-//! waiters associated with the lock. The lock owner, upon releasing the lock,
-//! will scan through the queue and wake up threads as appropriate, which will
-//! then again try to acquire the lock. The resulting [`RwLock`] is:
+//! Therefore, we implement our own [`RwLock`]! Naively, one might reach for a spinlock, but those
+//! can be quite [problematic] when the lock is contended.
 //!
-//! * adaptive, since it spins before doing any heavywheight parking operations
-//! * allocation-free, modulo the per-thread [`Thread`] handle, which is
-//! allocated regardless when using threads created by `std`
+//! Instead, this [`RwLock`] copies its implementation strategy from the Windows [SRWLOCK] and the
+//! [usync] library implementations.
+//!
+//! Spinning is still used for the fast path, but it is bounded: after spinning fails, threads will
+//! locklessly add an information structure ([`Node`]) containing a [`Thread`] handle into a queue
+//! of waiters associated with the lock. The lock owner, upon releasing the lock, will scan through
+//! the queue and wake up threads as appropriate, and the newly-awoken threads will then try to
+//! acquire the lock themselves.
+//!
+//! The resulting [`RwLock`] is:
+//!
+//! * adaptive, since it spins before doing any heavyweight parking operations
+//! * allocation-free, modulo the per-thread [`Thread`] handle, which is allocated anyways when
+//! using threads created by `std`
 //! * writer-preferring, even if some readers may still slip through
-//! * unfair, which reduces context-switching and thus drastically improves
-//! performance
+//! * unfair, which reduces context-switching and thus drastically improves performance
 //!
 //! and also quite fast in most cases.
 //!
-//! [can be quite problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html
+//! [problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html
 //! [SRWLOCK]: https://learn.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks
 //! [usync]: https://crates.io/crates/usync
 //!
@@ -39,33 +40,37 @@
 //!
 //! ## State
 //!
-//! A single [`AtomicPtr`] is used as state variable. The lowest three bits are used
-//! to indicate the meaning of the remaining bits:
+//! A single [`AtomicPtr`] is used as state variable. The lowest four bits are used to indicate the
+//! meaning of the remaining bits:
+//!
+//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | [`DOWNGRADED`] | Remaining    |                                                                                                                             |
+//! |------------|:-----------|:-----------------|:---------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------|
+//! | 0          | 0          | 0                | 0              | 0            | The lock is unlocked, no threads are waiting                                                                                |
+//! | 1          | 0          | 0                | 0              | 0            | The lock is write-locked, no threads waiting                                                                                |
+//! | 1          | 0          | 0                | 0              | n > 0        | The lock is read-locked with n readers                                                                                      |
+//! | 0          | 1          | *                | 0              | `*mut Node`  | The lock is unlocked, but some threads are waiting. Only writers may lock the lock                                          |
+//! | 1          | 1          | *                | *              | `*mut Node`  | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count |
+//!
+//! ## Waiter Queue
 //!
-//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | Remaining    |                                                                                                                             |
-//! |:-----------|:-----------|:-----------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------|
-//! | 0          | 0          | 0                | 0            | The lock is unlocked, no threads are waiting                                                                                |
-//! | 1          | 0          | 0                | 0            | The lock is write-locked, no threads waiting                                                                                |
-//! | 1          | 0          | 0                | n > 0        | The lock is read-locked with n readers                                                                                      |
-//! | 0          | 1          | *                | `*mut Node`  | The lock is unlocked, but some threads are waiting. Only writers may lock the lock                                          |
-//! | 1          | 1          | *                | `*mut Node`  | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count |
+//! When threads are waiting on the lock (the `QUEUE` bit is set), the lock state points to a queue
+//! of waiters, which is implemented as a linked list of nodes stored on the stack to avoid memory
+//! allocation.
 //!
-//! ## Waiter queue
+//! To enable lock-free enqueuing of new nodes to the queue, the linked list is singly-linked upon
+//! creation.
 //!
-//! When threads are waiting on the lock (`QUEUE` is set), the lock state
-//! points to a queue of waiters, which is implemented as a linked list of
-//! nodes stored on the stack to avoid memory allocation. To enable lockless
-//! enqueuing of new nodes to the queue, the linked list is single-linked upon
-//! creation. Since when the lock is read-locked, the lock count is stored in
-//! the last link of the queue, threads have to traverse the queue to find the
-//! last element upon releasing the lock. To avoid having to traverse the whole
-//! list again and again, a pointer to the found tail is cached in the (current)
-//! first element of the queue.
+//! When the lock is read-locked, the lock count (number of readers) is stored in the last link of
+//! the queue. Threads have to traverse the queue to find the last element upon releasing the lock.
+//! To avoid having to traverse the entire list every time we want to access the reader count, a
+//! pointer to the found tail is cached in the (current) first element of the queue.
 //!
-//! Also, while the lock is unfair for performance reasons, it is still best to
-//! wake the tail node first, which requires backlinks to previous nodes to be
-//! created. This is done at the same time as finding the tail, and thus a set
-//! tail field indicates the remaining portion of the queue is initialized.
+//! Also, while the lock is unfair for performance reasons, it is still best to wake the tail node
+//! first (FIFO ordering). Since we always pop nodes off the tail of the queue, we must store
+//! backlinks to previous nodes so that we can update the `tail` field of the (current) first
+//! element of the queue. Adding backlinks is done at the same time as finding the tail (via the
+//! function [`find_tail_and_add_backlinks`]), and thus encountering a set tail field on a node
+//! indicates that all following nodes in the queue are initialized.
 //!
 //! TLDR: Here's a diagram of what the queue looks like:
 //!
@@ -89,21 +94,21 @@
 //! 3. All nodes preceding this node must have a correct, non-null `next` field.
 //! 4. All nodes following this node must have a correct, non-null `prev` field.
 //!
-//! Access to the queue is controlled by the `QUEUE_LOCKED` bit, which threads
-//! try to set both after enqueuing themselves to eagerly add backlinks to the
-//! queue, which drastically improves performance, and after unlocking the lock
-//! to wake the next waiter(s). This is done atomically at the same time as the
-//! enqueuing/unlocking operation. The thread releasing the `QUEUE_LOCK` bit
-//! will check the state of the lock and wake up waiters as appropriate. This
-//! guarantees forward-progress even if the unlocking thread could not acquire
-//! the queue lock.
+//! Access to the queue is controlled by the `QUEUE_LOCKED` bit. Threads will try to set this bit
+//! in two cases: one is when a thread enqueues itself and eagerly adds backlinks to the queue
+//! (which drastically improves performance), and the other is after a thread unlocks the lock to
+//! wake up the next waiter(s).
 //!
-//! ## Memory orderings
+//! `QUEUE_LOCKED` is set atomically at the same time as the enqueuing/unlocking operations. The
+//! thread releasing the `QUEUE_LOCKED` bit will check the state of the lock (in particular, whether
+//! a downgrade was requested using the [`DOWNGRADED`] bit) and wake up waiters as appropriate. This
+//! guarantees forward progress even if the unlocking thread could not acquire the queue lock.
 //!
-//! To properly synchronize changes to the data protected by the lock, the lock
-//! is acquired and released with [`Acquire`] and [`Release`] ordering, respectively.
-//! To propagate the initialization of nodes, changes to the queue lock are also
-//! performed using these orderings.
+//! ## Memory Orderings
+//!
+//! To properly synchronize changes to the data protected by the lock, the lock is acquired and
+//! released with [`Acquire`] and [`Release`] ordering, respectively. To propagate the
+//! initialization of nodes, changes to the queue lock are also performed using these orderings.
 
 #![forbid(unsafe_op_in_unsafe_fn)]
 
@@ -115,26 +120,30 @@ use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicBool, AtomicPtr};
 use crate::thread::{self, Thread, ThreadId};
 
-// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
-// locking operation will be retried.
-// `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times.
-const SPIN_COUNT: usize = 7;
-
-type State = *mut ();
+/// The atomic lock state.
 type AtomicState = AtomicPtr<()>;
+/// The inner lock state.
+type State = *mut ();
 
 const UNLOCKED: State = without_provenance_mut(0);
-const LOCKED: usize = 1;
-const QUEUED: usize = 2;
-const QUEUE_LOCKED: usize = 4;
-const SINGLE: usize = 8;
-const MASK: usize = !(QUEUE_LOCKED | QUEUED | LOCKED);
+const LOCKED: usize = 1 << 0;
+const QUEUED: usize = 1 << 1;
+const QUEUE_LOCKED: usize = 1 << 2;
+const DOWNGRADED: usize = 1 << 3;
+const SINGLE: usize = 1 << 4;
+const STATE: usize = DOWNGRADED | QUEUE_LOCKED | QUEUED | LOCKED;
+const NODE_MASK: usize = !STATE;
+
+/// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the locking operation
+/// will be retried.
+///
+/// In other words, `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times.
+const SPIN_COUNT: usize = 7;
 
 /// Marks the state as write-locked, if possible.
 #[inline]
 fn write_lock(state: State) -> Option<State> {
-    let state = state.wrapping_byte_add(LOCKED);
-    if state.addr() & LOCKED == LOCKED { Some(state) } else { None }
+    if state.addr() & LOCKED == 0 { Some(state.map_addr(|addr| addr | LOCKED)) } else { None }
 }
 
 /// Marks the state as read-locked, if possible.
@@ -147,13 +156,32 @@ fn read_lock(state: State) -> Option<State> {
     }
 }
 
-/// Masks the state, assuming it points to a queue node.
+/// Converts a `State` into a `Node` by masking out the bottom bits of the state, assuming that the
+/// state points to a queue node.
 ///
 /// # Safety
+///
 /// The state must contain a valid pointer to a queue node.
 #[inline]
 unsafe fn to_node(state: State) -> NonNull<Node> {
-    unsafe { NonNull::new_unchecked(state.mask(MASK)).cast() }
+    unsafe { NonNull::new_unchecked(state.mask(NODE_MASK)).cast() }
+}
+
+/// The representation of a thread waiting on the lock queue.
+///
+/// We initialize these `Node`s on thread execution stacks to avoid allocation.
+///
+/// Note that we need an alignment of 16 to ensure that the last 4 bits of any
+/// pointers to `Node`s are always zeroed (for the bit flags described in the
+/// module-level documentation).
+#[repr(align(16))]
+struct Node {
+    next: AtomicLink,
+    prev: AtomicLink,
+    tail: AtomicLink,
+    write: bool,
+    thread: OnceCell<Thread>,
+    completed: AtomicBool,
 }
 
 /// An atomic node pointer with relaxed operations.
@@ -173,16 +201,6 @@ impl AtomicLink {
     }
 }
 
-#[repr(align(8))]
-struct Node {
-    next: AtomicLink,
-    prev: AtomicLink,
-    tail: AtomicLink,
-    write: bool,
-    thread: OnceCell<Thread>,
-    completed: AtomicBool,
-}
-
 impl Node {
     /// Creates a new queue node.
     fn new(write: bool) -> Node {
@@ -198,17 +216,17 @@ impl Node {
 
     /// Prepare this node for waiting.
     fn prepare(&mut self) {
-        // Fall back to creating an unnamed `Thread` handle to allow locking in
-        // TLS destructors.
+        // Fall back to creating an unnamed `Thread` handle to allow locking in TLS destructors.
         self.thread.get_or_init(|| {
             thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
         });
         self.completed = AtomicBool::new(false);
     }
 
-    /// Wait until this node is marked as completed.
+    /// Wait until this node is marked as [`complete`](Node::complete)d by another thread.
     ///
     /// # Safety
+    ///
     /// May only be called from the thread that created the node.
     unsafe fn wait(&self) {
         while !self.completed.load(Acquire) {
@@ -218,51 +236,48 @@ impl Node {
         }
     }
 
-    /// Atomically mark this node as completed. The node may not outlive this call.
-    unsafe fn complete(this: NonNull<Node>) {
-        // Since the node may be destroyed immediately after the completed flag
-        // is set, clone the thread handle before that.
-        let thread = unsafe { this.as_ref().thread.get().unwrap().clone() };
+    /// Atomically mark this node as completed.
+    ///
+    /// # Safety
+    ///
+    /// `node` must point to a valid `Node`, and the node may not outlive this call.
+    unsafe fn complete(node: NonNull<Node>) {
+        // Since the node may be destroyed immediately after the completed flag is set, clone the
+        // thread handle before that.
+        let thread = unsafe { node.as_ref().thread.get().unwrap().clone() };
         unsafe {
-            this.as_ref().completed.store(true, Release);
+            node.as_ref().completed.store(true, Release);
         }
         thread.unpark();
     }
 }
 
-struct PanicGuard;
-
-impl Drop for PanicGuard {
-    fn drop(&mut self) {
-        rtabort!("tried to drop node in intrusive list.");
-    }
-}
-
-/// Add backlinks to the queue, returning the tail.
+/// Traverse the queue and find the tail, adding backlinks to the queue while traversing.
 ///
-/// May be called from multiple threads at the same time, while the queue is not
+/// This may be called from multiple threads at the same time as long as the queue is not being
 /// modified (this happens when unlocking multiple readers).
 ///
 /// # Safety
+///
 /// * `head` must point to a node in a valid queue.
-/// * `head` must be or be in front of the head of the queue at the time of the
-/// last removal.
-/// * The part of the queue starting with `head` must not be modified during this
-/// call.
-unsafe fn add_backlinks_and_find_tail(head: NonNull<Node>) -> NonNull<Node> {
+/// * `head` must be in front of the previous head node that was used to perform the last removal.
+/// * The part of the queue starting with `head` must not be modified during this call.
+unsafe fn find_tail_and_add_backlinks(head: NonNull<Node>) -> NonNull<Node> {
     let mut current = head;
+
+    // Traverse the queue until we find a node that has a set `tail`.
     let tail = loop {
         let c = unsafe { current.as_ref() };
-        match c.tail.get() {
-            Some(tail) => break tail,
-            // SAFETY:
-            // All `next` fields before the first node with a `set` tail are
-            // non-null and valid (invariant 3).
-            None => unsafe {
-                let next = c.next.get().unwrap_unchecked();
-                next.as_ref().prev.set(Some(current));
-                current = next;
-            },
+        if let Some(tail) = c.tail.get() {
+            break tail;
+        }
+
+        // SAFETY: All `next` fields before the first node with a set `tail` are non-null and valid
+        // (by Invariant 3).
+        unsafe {
+            let next = c.next.get().unwrap_unchecked();
+            next.as_ref().prev.set(Some(current));
+            current = next;
         }
     };
 
@@ -272,6 +287,38 @@ unsafe fn add_backlinks_and_find_tail(head: NonNull<Node>) -> NonNull<Node> {
     }
 }
 
+/// [`complete`](Node::complete)s all threads in the queue ending with `tail`.
+///
+/// # Safety
+///
+/// * `tail` must be a valid tail of a fully linked queue.
+/// * The current thread must have exclusive access to that queue.
+unsafe fn complete_all(tail: NonNull<Node>) {
+    let mut current = tail;
+
+    // Traverse backwards through the queue (FIFO) and `complete` all of the nodes.
+    loop {
+        let prev = unsafe { current.as_ref().prev.get() };
+        unsafe {
+            Node::complete(current);
+        }
+        match prev {
+            Some(prev) => current = prev,
+            None => return,
+        }
+    }
+}
+
+/// A type to guard against the unwinds of stacks that nodes are located on due to panics.
+struct PanicGuard;
+
+impl Drop for PanicGuard {
+    fn drop(&mut self) {
+        rtabort!("tried to drop node in intrusive list.");
+    }
+}
+
+/// The public inner `RwLock` type.
 pub struct RwLock {
     state: AtomicState,
 }
@@ -296,11 +343,10 @@ impl RwLock {
 
     #[inline]
     pub fn try_write(&self) -> bool {
-        // Atomically set the `LOCKED` bit. This is lowered to a single atomic
-        // instruction on most modern processors (e.g. "lock bts" on x86 and
-        // "ldseta" on modern AArch64), and therefore is more efficient than
-        // `fetch_update(lock(true))`, which can spuriously fail if a new node
-        // is appended to the queue.
+        // Atomically set the `LOCKED` bit. This is lowered to a single atomic instruction on most
+        // modern processors (e.g. "lock bts" on x86 and "ldseta" on modern AArch64), and therefore
+        // is more efficient than `fetch_update(lock(true))`, which can spuriously fail if a new
+        // node is appended to the queue.
         self.state.fetch_or(LOCKED, Acquire).addr() & LOCKED == 0
     }
 
@@ -313,88 +359,97 @@ impl RwLock {
 
     #[cold]
     fn lock_contended(&self, write: bool) {
-        let update = if write { write_lock } else { read_lock };
         let mut node = Node::new(write);
         let mut state = self.state.load(Relaxed);
         let mut count = 0;
+        let update_fn = if write { write_lock } else { read_lock };
+
         loop {
-            if let Some(next) = update(state) {
+            // Optimistically update the state.
+            if let Some(next) = update_fn(state) {
                 // The lock is available, try locking it.
                 match self.state.compare_exchange_weak(state, next, Acquire, Relaxed) {
                     Ok(_) => return,
                     Err(new) => state = new,
                 }
+                continue;
             } else if state.addr() & QUEUED == 0 && count < SPIN_COUNT {
-                // If the lock is not available and no threads are queued, spin
-                // for a while, using exponential backoff to decrease cache
-                // contention.
+                // If the lock is not available and no threads are queued, optimistically spin for a
+                // while, using exponential backoff to decrease cache contention.
                 for _ in 0..(1 << count) {
                     spin_loop();
                 }
                 state = self.state.load(Relaxed);
                 count += 1;
+                continue;
+            }
+            // The optimistic paths did not succeed, so fall back to parking the thread.
+
+            // First, prepare the node.
+            node.prepare();
+
+            // If there are threads queued, this will set the `next` field to be a pointer to the
+            // first node in the queue.
+            // If the state is read-locked, this will set `next` to the lock count.
+            // If it is write-locked, it will set `next` to zero.
+            node.next.0 = AtomicPtr::new(state.mask(NODE_MASK).cast());
+            node.prev = AtomicLink::new(None);
+
+            // Set the `QUEUED` bit and preserve the `LOCKED` and `DOWNGRADED` bit.
+            let mut next = ptr::from_ref(&node)
+                .map_addr(|addr| addr | QUEUED | (state.addr() & (DOWNGRADED | LOCKED)))
+                as State;
+
+            let mut is_queue_locked = false;
+            if state.addr() & QUEUED == 0 {
+                // If this is the first node in the queue, set the `tail` field to the node itself
+                // to ensure there is a valid `tail` field in the queue (Invariants 1 & 2).
+                // This needs to use `set` to avoid invalidating the new pointer.
+                node.tail.set(Some(NonNull::from(&node)));
             } else {
-                // Fall back to parking. First, prepare the node.
-                node.prepare();
-
-                // If there are threads queued, set the `next` field to a
-                // pointer to the next node in the queue. Otherwise set it to
-                // the lock count if the state is read-locked or to zero if it
-                // is write-locked.
-                node.next.0 = AtomicPtr::new(state.mask(MASK).cast());
-                node.prev = AtomicLink::new(None);
-                let mut next = ptr::from_ref(&node)
-                    .map_addr(|addr| addr | QUEUED | (state.addr() & LOCKED))
-                    as State;
-
-                if state.addr() & QUEUED == 0 {
-                    // If this is the first node in the queue, set the tail field to
-                    // the node itself to ensure there is a current `tail` field in
-                    // the queue (invariants 1 and 2). This needs to use `set` to
-                    // avoid invalidating the new pointer.
-                    node.tail.set(Some(NonNull::from(&node)));
-                } else {
-                    // Otherwise, the tail of the queue is not known.
-                    node.tail.set(None);
-                    // Try locking the queue to eagerly add backlinks.
-                    next = next.map_addr(|addr| addr | QUEUE_LOCKED);
-                }
+                // Otherwise, the tail of the queue is not known.
+                node.tail.set(None);
 
-                // Register the node, using release ordering to propagate our
-                // changes to the waking thread.
-                if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) {
-                    // The state has changed, just try again.
-                    state = new;
-                    continue;
-                }
+                // Try locking the queue to eagerly add backlinks.
+                next = next.map_addr(|addr| addr | QUEUE_LOCKED);
 
-                // The node is registered, so the structure must not be
-                // mutably accessed or destroyed while other threads may
-                // be accessing it. Guard against unwinds using a panic
-                // guard that aborts when dropped.
-                let guard = PanicGuard;
+                // Track if we changed the `QUEUE_LOCKED` bit from off to on.
+                is_queue_locked = state.addr() & QUEUE_LOCKED == 0;
+            }
 
-                // If the current thread locked the queue, unlock it again,
-                // linking it in the process.
-                if state.addr() & (QUEUE_LOCKED | QUEUED) == QUEUED {
-                    unsafe {
-                        self.unlock_queue(next);
-                    }
-                }
+            // Register the node, using release ordering to propagate our changes to the waking
+            // thread.
+            if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) {
+                // The state has changed, just try again.
+                state = new;
+                continue;
+            }
+            // The node has been registered, so the structure must not be mutably accessed or
+            // destroyed while other threads may be accessing it.
 
-                // Wait until the node is removed from the queue.
-                // SAFETY: the node was created by the current thread.
+            // Guard against unwinds using a `PanicGuard` that aborts when dropped.
+            let guard = PanicGuard;
+
+            // If the current thread locked the queue, unlock it to eagerly adding backlinks.
+            if is_queue_locked {
+                // SAFETY: This thread set the `QUEUE_LOCKED` bit above.
                 unsafe {
-                    node.wait();
+                    self.unlock_queue(next);
                 }
+            }
 
-                // The node was removed from the queue, disarm the guard.
-                mem::forget(guard);
-
-                // Reload the state and try again.
-                state = self.state.load(Relaxed);
-                count = 0;
+            // Wait until the node is removed from the queue.
+            // SAFETY: the node was created by the current thread.
+            unsafe {
+                node.wait();
             }
+
+            // The node was removed from the queue, disarm the guard.
+            mem::forget(guard);
+
+            // Reload the state and try again.
+            state = self.state.load(Relaxed);
+            count = 0;
         }
     }
 
@@ -402,39 +457,51 @@ impl RwLock {
     pub unsafe fn read_unlock(&self) {
         match self.state.fetch_update(Release, Acquire, |state| {
             if state.addr() & QUEUED == 0 {
+                // If there are no threads queued, simply decrement the reader count.
                 let count = state.addr() - (SINGLE | LOCKED);
                 Some(if count > 0 { without_provenance_mut(count | LOCKED) } else { UNLOCKED })
+            } else if state.addr() & DOWNGRADED != 0 {
+                // This thread used to have exclusive access, but requested a downgrade. This has
+                // not been completed yet, so we still have exclusive access.
+                // Retract the downgrade request and unlock, but leave waking up new threads to the
+                // thread that already holds the queue lock.
+                Some(state.mask(!(DOWNGRADED | LOCKED)))
             } else {
                 None
             }
         }) {
             Ok(_) => {}
-            // There are waiters queued and the lock count was moved to the
-            // tail of the queue.
+            // There are waiters queued and the lock count was moved to the tail of the queue.
             Err(state) => unsafe { self.read_unlock_contended(state) },
         }
     }
 
+    /// # Safety
+    ///
+    /// * There must be threads queued on the lock.
+    /// * `state` must be a pointer to a node in a valid queue.
+    /// * There cannot be a `downgrade` in progress.
     #[cold]
     unsafe fn read_unlock_contended(&self, state: State) {
-        // The state was observed with acquire ordering above, so the current
-        // thread will observe all node initializations.
-
         // SAFETY:
-        // Because new read-locks cannot be acquired while threads are queued,
-        // all queue-lock owners will observe the set `LOCKED` bit. Because they
-        // do not modify the queue while there is a lock owner, the queue will
-        // not be removed from here.
-        let tail = unsafe { add_backlinks_and_find_tail(to_node(state)).as_ref() };
+        // The state was observed with acquire ordering above, so the current thread will have
+        // observed all node initializations.
+        // We also know that no threads can be modifying the queue starting at `state`: because new
+        // read-locks cannot be acquired while there are any threads queued on the lock, all
+        // queue-lock owners will observe a set `LOCKED` bit in `self.state` and will not modify
+        // the queue. The other case that a thread could modify the queue is if a downgrade is in
+        // progress (removal of the entire queue), but since that is part of this function's safety
+        // contract, we can guarantee that no other threads can modify the queue.
+        let tail = unsafe { find_tail_and_add_backlinks(to_node(state)).as_ref() };
+
         // The lock count is stored in the `next` field of `tail`.
-        // Decrement it, making sure to observe all changes made to the queue
-        // by the other lock owners by using acquire-release ordering.
+        // Decrement it, making sure to observe all changes made to the queue by the other lock
+        // owners by using acquire-release ordering.
         let was_last = tail.next.0.fetch_byte_sub(SINGLE, AcqRel).addr() - SINGLE == 0;
         if was_last {
-            // SAFETY:
-            // Other threads cannot read-lock while threads are queued. Also,
-            // the `LOCKED` bit is still set, so there are no writers. Therefore,
-            // the current thread exclusively owns the lock.
+            // SAFETY: Other threads cannot read-lock while threads are queued. Also, the `LOCKED`
+            // bit is still set, so there are no writers. Thus the current thread exclusively owns
+            // this lock, even though it is a reader.
             unsafe { self.unlock_contended(state) }
         }
     }
@@ -444,49 +511,143 @@ impl RwLock {
         if let Err(state) =
             self.state.compare_exchange(without_provenance_mut(LOCKED), UNLOCKED, Release, Relaxed)
         {
-            // SAFETY:
-            // Since other threads cannot acquire the lock, the state can only
-            // have changed because there are threads queued on the lock.
+            // SAFETY: Since other threads cannot acquire the lock, the state can only have changed
+            // because there are threads queued on the lock.
             unsafe { self.unlock_contended(state) }
         }
     }
 
     /// # Safety
+    ///
     /// * The lock must be exclusively owned by this thread.
     /// * There must be threads queued on the lock.
+    /// * `state` must be a pointer to a node in a valid queue.
+    /// * There cannot be a `downgrade` in progress.
     #[cold]
-    unsafe fn unlock_contended(&self, mut state: State) {
+    unsafe fn unlock_contended(&self, state: State) {
+        debug_assert_eq!(state.addr() & (DOWNGRADED | QUEUED | LOCKED), QUEUED | LOCKED);
+
+        let mut current = state;
+
+        // We want to atomically release the lock and try to acquire the queue lock.
         loop {
+            // First check if the queue lock is already held.
+            if current.addr() & QUEUE_LOCKED != 0 {
+                // Another thread holds the queue lock, so let them wake up waiters for us.
+                let next = current.mask(!LOCKED);
+                match self.state.compare_exchange_weak(current, next, Release, Relaxed) {
+                    Ok(_) => return,
+                    Err(new) => {
+                        current = new;
+                        continue;
+                    }
+                }
+            }
+
             // Atomically release the lock and try to acquire the queue lock.
-            let next = state.map_addr(|a| (a & !LOCKED) | QUEUE_LOCKED);
-            match self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) {
-                // The queue lock was acquired. Release it, waking up the next
-                // waiter in the process.
-                Ok(_) if state.addr() & QUEUE_LOCKED == 0 => unsafe {
-                    return self.unlock_queue(next);
-                },
-                // Another thread already holds the queue lock, leave waking up
-                // waiters to it.
-                Ok(_) => return,
-                Err(new) => state = new,
+            let next = current.map_addr(|addr| (addr & !LOCKED) | QUEUE_LOCKED);
+            match self.state.compare_exchange_weak(current, next, AcqRel, Relaxed) {
+                // Now that we have the queue lock, we can wake up the next waiter.
+                Ok(_) => {
+                    // SAFETY: This thread just acquired the queue lock, and this function's safety
+                    // contract requires that there are threads already queued on the lock.
+                    unsafe { self.unlock_queue(next) };
+                    return;
+                }
+                Err(new) => current = new,
             }
         }
     }
 
-    /// Unlocks the queue. If the lock is unlocked, wakes up the next eligible
-    /// thread(s).
+    /// # Safety
+    ///
+    /// * The lock must be write-locked by this thread.
+    #[inline]
+    pub unsafe fn downgrade(&self) {
+        // Optimistically change the state from write-locked with a single writer and no waiters to
+        // read-locked with a single reader and no waiters.
+        if let Err(state) = self.state.compare_exchange(
+            without_provenance_mut(LOCKED),
+            without_provenance_mut(SINGLE | LOCKED),
+            Release,
+            Relaxed,
+        ) {
+            // SAFETY: The only way the state can have changed is if there are threads queued.
+            // Wake all of them up.
+            unsafe { self.downgrade_slow(state) }
+        }
+    }
+
+    /// Downgrades the lock from write-locked to read-locked in the case that there are threads
+    /// waiting on the wait queue.
+    ///
+    /// This function will either wake up all of the waiters on the wait queue or designate the
+    /// current holder of the queue lock to wake up all of the waiters instead. Once the waiters
+    /// wake up, they will continue in the execution loop of `lock_contended`.
     ///
     /// # Safety
-    /// The queue lock must be held by the current thread.
+    ///
+    /// * The lock must be write-locked by this thread.
+    /// * `state` must be a pointer to a node in a valid queue.
+    /// * There must be threads queued on the lock.
+    #[cold]
+    unsafe fn downgrade_slow(&self, mut state: State) {
+        debug_assert_eq!(state.addr() & (DOWNGRADED | QUEUED | LOCKED), QUEUED | LOCKED);
+
+        // Attempt to wake up all waiters by taking ownership of the entire waiter queue.
+        loop {
+            if state.addr() & QUEUE_LOCKED != 0 {
+                // Another thread already holds the queue lock. Tell it to wake up all waiters.
+                // If the other thread succeeds in waking up waiters before we release our lock, the
+                // effect will be just the same as if we had changed the state below.
+                // Otherwise, the `DOWNGRADED` bit will still be set, meaning that when this thread
+                // calls `read_unlock` later (because it holds a read lock and must unlock
+                // eventually), it will realize that the lock is still exclusively locked and act
+                // accordingly.
+                let next = state.map_addr(|addr| addr | DOWNGRADED);
+                match self.state.compare_exchange_weak(state, next, Release, Relaxed) {
+                    Ok(_) => return,
+                    Err(new) => state = new,
+                }
+            } else {
+                // Grab the entire queue by swapping the `state` with a single reader.
+                let next = ptr::without_provenance_mut(SINGLE | LOCKED);
+                if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) {
+                    state = new;
+                    continue;
+                }
+
+                // SAFETY: We have full ownership of this queue now, so nobody else can modify it.
+                let tail = unsafe { find_tail_and_add_backlinks(to_node(state)) };
+
+                // Wake up all waiters.
+                // SAFETY: `tail` was just computed, meaning the whole queue is linked, and we have
+                // full ownership of the queue, so we have exclusive access.
+                unsafe { complete_all(tail) };
+
+                return;
+            }
+        }
+    }
+
+    /// Unlocks the queue. Wakes up all threads if a downgrade was requested, otherwise wakes up the
+    /// next eligible thread(s) if the lock is unlocked.
+    ///
+    /// # Safety
+    ///
+    /// * The queue lock must be held by the current thread.
+    /// * `state` must be a pointer to a node in a valid queue.
+    /// * There must be threads queued on the lock.
     unsafe fn unlock_queue(&self, mut state: State) {
         debug_assert_eq!(state.addr() & (QUEUED | QUEUE_LOCKED), QUEUED | QUEUE_LOCKED);
 
         loop {
-            let tail = unsafe { add_backlinks_and_find_tail(to_node(state)) };
+            // SAFETY: Since we have the queue lock, nobody else can be modifying the queue.
+            let tail = unsafe { find_tail_and_add_backlinks(to_node(state)) };
 
-            if state.addr() & LOCKED == LOCKED {
-                // Another thread has locked the lock. Leave waking up waiters
-                // to them by releasing the queue lock.
+            if state.addr() & (DOWNGRADED | LOCKED) == LOCKED {
+                // Another thread has locked the lock and no downgrade was requested.
+                // Leave waking up waiters to them by releasing the queue lock.
                 match self.state.compare_exchange_weak(
                     state,
                     state.mask(!QUEUE_LOCKED),
@@ -501,53 +662,63 @@ impl RwLock {
                 }
             }
 
+            // Since we hold the queue lock and downgrades cannot be requested if the lock is
+            // already read-locked, we have exclusive control over the queue here and can make
+            // modifications.
+
+            let downgrade = state.addr() & DOWNGRADED != 0;
             let is_writer = unsafe { tail.as_ref().write };
-            if is_writer && let Some(prev) = unsafe { tail.as_ref().prev.get() } {
-                // `tail` is a writer and there is a node before `tail`.
-                // Split off `tail`.
+            if !downgrade
+                && is_writer
+                && let Some(prev) = unsafe { tail.as_ref().prev.get() }
+            {
+                // If we are not downgrading and the next thread is a writer, only wake up that
+                // writing thread.
 
-                // There are no set `tail` links before the node pointed to by
-                // `state`, so the first non-null tail field will be current
-                // (invariant 2). Invariant 4 is fullfilled since `find_tail`
-                // was called on this node, which ensures all backlinks are set.
+                // Split off `tail`.
+                // There are no set `tail` links before the node pointed to by `state`, so the first
+                // non-null tail field will be current (Invariant 2).
+                // We also fulfill Invariant 4 since `find_tail` was called on this node, which
+                // ensures all backlinks are set.
                 unsafe {
                     to_node(state).as_ref().tail.set(Some(prev));
                 }
 
-                // Release the queue lock. Doing this by subtraction is more
-                // efficient on modern processors since it is a single instruction
-                // instead of an update loop, which will fail if new threads are
-                // added to the list.
-                self.state.fetch_byte_sub(QUEUE_LOCKED, Release);
+                // Try to release the queue lock. We need to check the state again since another
+                // thread might have acquired the lock and requested a downgrade.
+                let next = state.mask(!QUEUE_LOCKED);
+                if let Err(new) = self.state.compare_exchange_weak(state, next, Release, Acquire) {
+                    // Undo the tail modification above, so that we can find the tail again above.
+                    // As mentioned above, we have exclusive control over the queue, so no other
+                    // thread could have noticed the change.
+                    unsafe {
+                        to_node(state).as_ref().tail.set(Some(tail));
+                    }
+                    state = new;
+                    continue;
+                }
 
-                // The tail was split off and the lock released. Mark the node as
-                // completed.
+                // The tail was split off and the lock was released. Mark the node as completed.
                 unsafe {
                     return Node::complete(tail);
                 }
             } else {
-                // The next waiter is a reader or the queue only consists of one
-                // waiter. Just wake all threads.
-
-                // The lock cannot be locked (checked above), so mark it as
-                // unlocked to reset the queue.
-                if let Err(new) =
-                    self.state.compare_exchange_weak(state, UNLOCKED, Release, Acquire)
-                {
+                // We are either downgrading, the next waiter is a reader, or the queue only
+                // consists of one waiter. In any case, just wake all threads.
+
+                // Clear the queue.
+                let next =
+                    if downgrade { ptr::without_provenance_mut(SINGLE | LOCKED) } else { UNLOCKED };
+                if let Err(new) = self.state.compare_exchange_weak(state, next, Release, Acquire) {
                     state = new;
                     continue;
                 }
 
-                let mut current = tail;
-                loop {
-                    let prev = unsafe { current.as_ref().prev.get() };
-                    unsafe {
-                        Node::complete(current);
-                    }
-                    match prev {
-                        Some(prev) => current = prev,
-                        None => return,
-                    }
+                // SAFETY: we computed `tail` above, and no new nodes can have been added since
+                // (otherwise the CAS above would have failed).
+                // Thus we have complete control over the whole queue.
+                unsafe {
+                    return complete_all(tail);
                 }
             }
         }
diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs
index 7703082f951..f664fef9074 100644
--- a/library/std/src/sys/sync/rwlock/solid.rs
+++ b/library/std/src/sys/sync/rwlock/solid.rs
@@ -79,6 +79,12 @@ impl RwLock {
         let rwl = self.raw();
         expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
     }
+
+    #[inline]
+    pub unsafe fn downgrade(&self) {
+        // The SOLID platform does not support the `downgrade` operation for reader writer locks, so
+        // this function is simply a no-op as only 1 reader can read: the original writer.
+    }
 }
 
 impl Drop for RwLock {
diff --git a/library/std/src/sys/sync/rwlock/teeos.rs b/library/std/src/sys/sync/rwlock/teeos.rs
index 76343022383..4a71a3abc27 100644
--- a/library/std/src/sys/sync/rwlock/teeos.rs
+++ b/library/std/src/sys/sync/rwlock/teeos.rs
@@ -41,4 +41,10 @@ impl RwLock {
     pub unsafe fn write_unlock(&self) {
         unsafe { self.inner.unlock() };
     }
+
+    #[inline]
+    pub unsafe fn downgrade(&self) {
+        // Since there is no difference between read-locked and write-locked on this platform, this
+        // function is simply a no-op as only 1 reader can read: the original writer.
+    }
 }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 227ee9d64f3..2c2cc58a9dd 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -188,6 +188,11 @@ mod current;
 pub use current::current;
 pub(crate) use current::{current_id, drop_current, set_current, try_current};
 
+mod spawnhook;
+
+#[unstable(feature = "thread_spawn_hook", issue = "132951")]
+pub use spawnhook::add_spawn_hook;
+
 ////////////////////////////////////////////////////////////////////////////////
 // Thread-local storage
 ////////////////////////////////////////////////////////////////////////////////
@@ -259,6 +264,8 @@ pub struct Builder {
     name: Option<String>,
     // The size of the stack for the spawned thread in bytes
     stack_size: Option<usize>,
+    // Skip running and inheriting the thread spawn hooks
+    no_hooks: bool,
 }
 
 impl Builder {
@@ -282,7 +289,7 @@ impl Builder {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> Builder {
-        Builder { name: None, stack_size: None }
+        Builder { name: None, stack_size: None, no_hooks: false }
     }
 
     /// Names the thread-to-be. Currently the name is used for identification
@@ -338,6 +345,16 @@ impl Builder {
         self
     }
 
+    /// Disables running and inheriting [spawn hooks](add_spawn_hook).
+    ///
+    /// Use this if the parent thread is in no way relevant for the child thread.
+    /// For example, when lazily spawning threads for a thread pool.
+    #[unstable(feature = "thread_spawn_hook", issue = "132951")]
+    pub fn no_hooks(mut self) -> Builder {
+        self.no_hooks = true;
+        self
+    }
+
     /// Spawns a new thread by taking ownership of the `Builder`, and returns an
     /// [`io::Result`] to its [`JoinHandle`].
     ///
@@ -460,7 +477,7 @@ impl Builder {
         F: Send,
         T: Send,
     {
-        let Builder { name, stack_size } = self;
+        let Builder { name, stack_size, no_hooks } = self;
 
         let stack_size = stack_size.unwrap_or_else(|| {
             static MIN: AtomicUsize = AtomicUsize::new(0);
@@ -485,6 +502,13 @@ impl Builder {
             Some(name) => Thread::new(id, name.into()),
             None => Thread::new_unnamed(id),
         };
+
+        let hooks = if no_hooks {
+            spawnhook::ChildSpawnHooks::default()
+        } else {
+            spawnhook::run_spawn_hooks(&my_thread)
+        };
+
         let their_thread = my_thread.clone();
 
         let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -494,9 +518,6 @@ impl Builder {
         });
         let their_packet = my_packet.clone();
 
-        let output_capture = crate::io::set_output_capture(None);
-        crate::io::set_output_capture(output_capture.clone());
-
         // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*.
         // See <https://github.com/rust-lang/rust/issues/101983> for more details.
         // To prevent leaks we use a wrapper that drops its contents.
@@ -534,10 +555,9 @@ impl Builder {
                 imp::Thread::set_name(name);
             }
 
-            crate::io::set_output_capture(output_capture);
-
             let f = f.into_inner();
             let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+                crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run());
                 crate::sys::backtrace::__rust_begin_short_backtrace(f)
             }));
             // SAFETY: `their_packet` as been built just above and moved by the
diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs
new file mode 100644
index 00000000000..99b5ad9cb9f
--- /dev/null
+++ b/library/std/src/thread/spawnhook.rs
@@ -0,0 +1,148 @@
+use crate::cell::Cell;
+use crate::iter;
+use crate::sync::Arc;
+use crate::thread::Thread;
+
+crate::thread_local! {
+    /// A thread local linked list of spawn hooks.
+    ///
+    /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads.
+    ///
+    /// (That technically makes it a set of linked lists with shared tails, so a linked tree.)
+    static SPAWN_HOOKS: Cell<SpawnHooks> = const { Cell::new(SpawnHooks { first: None }) };
+}
+
+#[derive(Default, Clone)]
+struct SpawnHooks {
+    first: Option<Arc<SpawnHook>>,
+}
+
+// Manually implement drop to prevent deep recursion when dropping linked Arc list.
+impl Drop for SpawnHooks {
+    fn drop(&mut self) {
+        let mut next = self.first.take();
+        while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) {
+            drop(hook);
+            next = n;
+        }
+    }
+}
+
+struct SpawnHook {
+    hook: Box<dyn Send + Sync + Fn(&Thread) -> Box<dyn Send + FnOnce()>>,
+    next: Option<Arc<SpawnHook>>,
+}
+
+/// Registers a function to run for every newly thread spawned.
+///
+/// The hook is executed in the parent thread, and returns a function
+/// that will be executed in the new thread.
+///
+/// The hook is called with the `Thread` handle for the new thread.
+///
+/// The hook will only be added for the current thread and is inherited by the threads it spawns.
+/// In other words, adding a hook has no effect on already running threads (other than the current
+/// thread) and the threads they might spawn in the future.
+///
+/// Hooks can only be added, not removed.
+///
+/// The hooks will run in reverse order, starting with the most recently added.
+///
+/// # Usage
+///
+/// ```
+/// #![feature(thread_spawn_hook)]
+///
+/// std::thread::add_spawn_hook(|_| {
+///     ..; // This will run in the parent (spawning) thread.
+///     move || {
+///         ..; // This will run it the child (spawned) thread.
+///     }
+/// });
+/// ```
+///
+/// # Example
+///
+/// A spawn hook can be used to "inherit" a thread local from the parent thread:
+///
+/// ```
+/// #![feature(thread_spawn_hook)]
+///
+/// use std::cell::Cell;
+///
+/// thread_local! {
+///     static X: Cell<u32> = Cell::new(0);
+/// }
+///
+/// // This needs to be done once in the main thread before spawning any threads.
+/// std::thread::add_spawn_hook(|_| {
+///     // Get the value of X in the spawning thread.
+///     let value = X.get();
+///     // Set the value of X in the newly spawned thread.
+///     move || X.set(value)
+/// });
+///
+/// X.set(123);
+///
+/// std::thread::spawn(|| {
+///     assert_eq!(X.get(), 123);
+/// }).join().unwrap();
+/// ```
+#[unstable(feature = "thread_spawn_hook", issue = "132951")]
+pub fn add_spawn_hook<F, G>(hook: F)
+where
+    F: 'static + Send + Sync + Fn(&Thread) -> G,
+    G: 'static + Send + FnOnce(),
+{
+    SPAWN_HOOKS.with(|h| {
+        let mut hooks = h.take();
+        let next = hooks.first.take();
+        hooks.first = Some(Arc::new(SpawnHook {
+            hook: Box::new(move |thread| Box::new(hook(thread))),
+            next,
+        }));
+        h.set(hooks);
+    });
+}
+
+/// Runs all the spawn hooks.
+///
+/// Called on the parent thread.
+///
+/// Returns the functions to be called on the newly spawned thread.
+pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks {
+    // Get a snapshot of the spawn hooks.
+    // (Increments the refcount to the first node.)
+    let hooks = SPAWN_HOOKS.with(|hooks| {
+        let snapshot = hooks.take();
+        hooks.set(snapshot.clone());
+        snapshot
+    });
+    // Iterate over the hooks, run them, and collect the results in a vector.
+    let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref())
+        .map(|hook| (hook.hook)(thread))
+        .collect();
+    // Pass on the snapshot of the hooks and the results to the new thread,
+    // which will then run SpawnHookResults::run().
+    ChildSpawnHooks { hooks, to_run }
+}
+
+/// The results of running the spawn hooks.
+///
+/// This struct is sent to the new thread.
+/// It contains the inherited hooks and the closures to be run.
+#[derive(Default)]
+pub(super) struct ChildSpawnHooks {
+    hooks: SpawnHooks,
+    to_run: Vec<Box<dyn FnOnce() + Send>>,
+}
+
+impl ChildSpawnHooks {
+    // This is run on the newly spawned thread, directly at the start.
+    pub(super) fn run(self) {
+        SPAWN_HOOKS.set(self.hooks);
+        for run in self.to_run {
+            run();
+        }
+    }
+}
diff --git a/library/stdarch b/library/stdarch
-Subproject ff9a4445038eae46fd095188740946808581bc0
+Subproject e5e00aab0a8c8fa35fb7865e88fa82366f615c5
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 30ccfe2af8d..47407df909b 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -24,6 +24,7 @@
 #![feature(process_exitcode_internals)]
 #![feature(panic_can_unwind)]
 #![feature(test)]
+#![feature(thread_spawn_hook)]
 #![allow(internal_features)]
 #![warn(rustdoc::unescaped_backticks)]
 
@@ -134,6 +135,16 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
                 }
             });
             panic::set_hook(hook);
+            // Use a thread spawning hook to make new threads inherit output capturing.
+            std::thread::add_spawn_hook(|_| {
+                // Get and clone the output capture of the current thread.
+                let output_capture = io::set_output_capture(None);
+                io::set_output_capture(output_capture.clone());
+                // Set the output capture of the new thread.
+                || {
+                    io::set_output_capture(output_capture);
+                }
+            });
         }
         let res = console::run_tests_console(&opts, tests);
         // Prevent Valgrind from reporting reachable blocks in users' unit tests.
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 95b1303fa71..e706aba977b 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1255,6 +1255,10 @@ impl Config {
             },
             out: PathBuf::from("build"),
 
+            // This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to
+            // `rust-objcopy` to workaround bad `strip`s on macOS.
+            llvm_tools_enabled: true,
+
             ..Default::default()
         }
     }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 1d05f94e3be..7f62ffb20db 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -300,4 +300,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "`download-rustc='if-unchanged'` is now a default option for library profile.",
     },
+    ChangeInfo {
+        change_id: 133207,
+        severity: ChangeSeverity::Info,
+        summary: "`rust.llvm-tools` is now enabled by default when no `config.toml` is provided.",
+    },
 ];
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
index dcfea77149e..eb39861d8c7 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
@@ -55,4 +55,4 @@ ENV RUST_CONFIGURE_ARGS \
 
 ENV SCRIPT \
   python3 ../x.py --stage 2 build && \
-  python3 ../x.py --stage 2 test tests/run-make --test-args clang
+  python3 ../x.py --stage 2 test tests/run-make
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 340dfd67b7d..9a51a3f4268 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -465,7 +465,7 @@ auto:
       SCRIPT: python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-windows-8c
+    <<: *job-windows
 
   - image: dist-aarch64-msvc
     env:
@@ -477,7 +477,7 @@ auto:
         --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
-    <<: *job-windows-8c
+    <<: *job-windows
 
   - image: dist-i686-mingw
     env:
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 2d482e203eb6d6e353814cf1415c5f94e590b9e
+Subproject 915f9b319c2823f310430ecdecd86264a7870d7
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 456b904f791751892b01282fd2757904993c4c2
+Subproject eac89a3cbe6c4714e5029ae8b5a1c556fd4e8c4
diff --git a/src/doc/reference b/src/doc/reference
-Subproject da0f6dad767670da0e8cd5af8a7090db3272f62
+Subproject 41ccb0e6478305401dad92e8fd3d04a4304edb4
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 6a5accdaf10255882b1e6c59dfe5f1c79ac9548
+Subproject b679e71c2d66c6fe13e06b99ac61773b866213f
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 18f76ac6fe0..f3d8a4edd6c 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -72,6 +72,8 @@
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
     - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
+    - [s390x-unknown-linux-gnu](platform-support/s390x-unknown-linux-gnu.md)
+    - [s390x-unknown-linux-musl](platform-support/s390x-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 500eaafb63f..243cb3b2fc8 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -99,7 +99,7 @@ target | notes
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
 [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
 [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
-`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
+[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17)
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3
@@ -367,7 +367,7 @@ target | std | host | notes
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 [`riscv64-linux-android`](platform-support/android.md) |   |   | RISC-V 64-bit Android
 [`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
-`s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, musl 1.2.3)
+[`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) |  |  | S390x Linux (kernel 3.2, musl 1.2.3)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * |  | Bare 32-bit SPARC V7+
 [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md
new file mode 100644
index 00000000000..60e06c404c0
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md
@@ -0,0 +1,113 @@
+# `s390x-unknown-linux-gnu`
+
+**Tier: 2 (with Host Tools)**
+
+IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux.
+
+## Target maintainers
+
+- Ulrich Weigand, <ulrich.weigand@de.ibm.com>, [@uweigand](https://github.com/uweigand)
+- Josh Stone, <jistone@redhat.com>, [@cuviper](https://github.com/cuviper)
+
+## Requirements
+
+This target requires:
+
+* Linux Kernel version 3.2 or later
+* glibc 2.17 or later
+
+Code generated by the target uses the z/Architecture ISA assuming a minimum
+architecture level of z10 (Eighth Edition of the z/Architecture Principles
+of Operation), and is compliant with the s390x ELF ABI.
+
+Reference material:
+
+* [z/Architecture Principles of Operation][s390x-isa]
+* [z/Architecture ELF Application Binary Interface][s390x-abi]
+
+[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf
+[s390x-abi]: https://github.com/IBM/s390x-abi
+
+## Building the target
+
+This target is distributed through `rustup`, and otherwise requires no
+special configuration.
+
+If you need to build your own Rust for some reason though, the target can be
+enabled in `config.toml`. For example:
+
+```toml
+[build]
+target = ["s390x-unknown-linux-gnu"]
+```
+
+## Building Rust programs
+
+On a s390x Linux host, the `s390x-unknown-linux-gnu` target should be
+automatically installed and used by default.
+
+On a non-s390x host, add the target:
+
+```bash
+rustup target add s390x-unknown-linux-gnu
+```
+
+Then cross compile crates with:
+
+```bash
+cargo build --target s390x-unknown-linux-gnu
+```
+
+## Testing
+
+There are no special requirements for testing and running the target.
+For testing cross builds on the host, please refer to the "Cross-compilation
+toolchains and C code" section below.
+
+## Cross-compilation toolchains and C code
+
+Rust code built using the target is compatible with C code compiled with
+GCC or Clang using the `s390x-unknown-linux-gnu` target triple (via either
+native or cross-compilation).
+
+On Ubuntu, a s390x cross-toolchain can be installed with:
+
+```bash
+apt install gcc-s390x-linux-gnu g++-s390x-linux-gnu libc6-dev-s390x-cross
+```
+
+Depending on your system, you may need to configure the target to use the GNU
+GCC linker. To use it, add the following to your `.cargo/config.toml`:
+
+```toml
+[target.s390x-unknown-linux-gnu]
+linker = "s390x-linux-gnu-gcc"
+```
+
+If your `s390x-linux-gnu-*` toolchain is not in your `PATH` you may need to
+configure additional settings:
+
+```toml
+[target.s390x-unknown-linux-gnu]
+# Adjust the paths to point at your toolchain
+cc = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-gcc"
+cxx = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-g++"
+ar = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-ar"
+ranlib = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-ranlib"
+linker = "/TOOLCHAIN_PATH/bin/s390x-linux-gnu-gcc"
+```
+
+To test cross compiled binaries on a non-s390x host, you can use
+[`qemu`](https://www.qemu.org/docs/master/system/target-s390x.html).
+On Ubuntu, a s390x emulator can be obtained with:
+
+```bash
+apt install qemu-system-s390x
+```
+
+Then, in `.cargo/config.toml` set the `runner`:
+
+```toml
+[target.s390x-unknown-linux-gnu]
+runner = "qemu-s390x-static -L /usr/s390x-linux-gnu"
+```
diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md
new file mode 100644
index 00000000000..e00f8db7f8e
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md
@@ -0,0 +1,83 @@
+# `s390x-unknown-linux-musl`
+
+**Tier: 3**
+
+IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux.
+
+## Target maintainers
+
+- Ulrich Weigand, <ulrich.weigand@de.ibm.com>, [@uweigand](https://github.com/uweigand)
+
+## Requirements
+
+This target requires:
+
+* Linux Kernel version 3.2 or later
+* musl 1.2.3 or later
+
+Code generated by the target uses the z/Architecture ISA assuming a minimum
+architecture level of z10 (Eighth Edition of the z/Architecture Principles
+of Operation), and is compliant with the s390x ELF ABI.
+
+Reference material:
+
+* [z/Architecture Principles of Operation][s390x-isa]
+* [z/Architecture ELF Application Binary Interface][s390x-abi]
+
+[s390x-isa]: https://publibfp.dhe.ibm.com/epubs/pdf/a227832d.pdf
+[s390x-abi]: https://github.com/IBM/s390x-abi
+
+## Building the target
+
+Because it is Tier 3, Rust does not yet ship pre-compiled artifacts for this
+target.
+
+Therefore, you can build Rust with support for the target by adding it to the
+target list in `config.toml`, a sample configuration is shown below.
+
+```toml
+[build]
+target = ["s390x-unknown-linux-musl"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will first need to build Rust with the target enabled (see
+"Building the target" above).
+
+## Testing
+
+There are no special requirements for testing and running the target.
+For testing cross builds on the host, please refer to the "Cross-compilation
+toolchains and C code" section below.
+
+## Cross-compilation toolchains and C code
+
+Rust code built using the target is compatible with C code compiled with
+GCC or Clang using the `s390x-unknown-linux-musl` target triple (via either
+native or cross-compilation).
+
+Depending on your system, you may need to configure the target to use the GNU
+GCC linker. To use it, add the following to your `.cargo/config.toml`:
+
+```toml
+[target.s390x-unknown-linux-musl]
+linker = "s390x-linux-musl-gcc"
+```
+
+If your `s390x-linux-musl-*` toolchain is not in your `PATH` you may need to
+configure additional settings:
+
+```toml
+[target.s390x-unknown-linux-musl]
+# Adjust the paths to point at your toolchain
+cc = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-gcc"
+cxx = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-g++"
+ar = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-ar"
+ranlib = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-ranlib"
+linker = "/TOOLCHAIN_PATH/bin/s390x-linux-musl-gcc"
+```
+
+To test cross compiled binaries on a non-s390x host, you can use
+[`qemu`](https://www.qemu.org/docs/master/system/target-s390x.html).
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md
index bb2348b201e..40049ecfa5f 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md
@@ -1,6 +1,6 @@
 # `wasm32-wasip2`
 
-**Tier: 3**
+**Tier: 2**
 
 The `wasm32-wasip2` target is a new and still (as of January 2024) an
 experimental target. This target is an extension to `wasm32-wasip1` target,
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index f8fb5284472..1af5e2b0e1d 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -447,32 +447,3 @@ This flag is **deprecated** and **has no effect**.
 Rustdoc only supports Rust source code and Markdown input formats. If the
 file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file.
 Otherwise, it assumes that the input file is Rust.
-
-## `--test-builder`: `rustc`-like program to build tests
-
-Using this flag looks like this:
-
-```bash
-$ rustdoc --test-builder /path/to/rustc src/lib.rs
-```
-
-Rustdoc will use the provided program to compile tests instead of the default `rustc` program from
-the sysroot.
-
-## `--test-builder-wrapper`: wrap calls to the test builder
-
-Using this flag looks like this:
-
-```bash
-$ rustdoc --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs
-$ rustdoc \
-    --test-builder-wrapper rustc-wrapper1 \
-    --test-builder-wrapper rustc-wrapper2 \
-    --test-builder rustc \
-    src/lib.rs
-```
-
-Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program.
-The first argument to the program will be the test builder program.
-
-This flag can be passed multiple times to nest wrappers.
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index ebbe141b6f5..e9524c0b78d 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -627,3 +627,36 @@ add the `--scrape-tests` flag.
 
 This flag enables the generation of links in the source code pages which allow the reader
 to jump to a type definition.
+
+### `--test-builder`: `rustc`-like program to build tests
+
+ * Tracking issue: [#102981](https://github.com/rust-lang/rust/issues/102981)
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc --test-builder /path/to/rustc src/lib.rs
+```
+
+Rustdoc will use the provided program to compile tests instead of the default `rustc` program from
+the sysroot.
+
+### `--test-builder-wrapper`: wrap calls to the test builder
+
+ * Tracking issue: [#102981](https://github.com/rust-lang/rust/issues/102981)
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc -Zunstable-options --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs
+$ rustdoc -Zunstable-options \
+    --test-builder-wrapper rustc-wrapper1 \
+    --test-builder-wrapper rustc-wrapper2 \
+    --test-builder rustc \
+    src/lib.rs
+```
+
+Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program.
+The first argument to the program will be the test builder program.
+
+This flag can be passed multiple times to nest wrappers.
diff --git a/src/doc/unstable-book/src/language-features/asm-goto.md b/src/doc/unstable-book/src/language-features/asm-goto.md
index d72eb7c0c6e..823118bcae1 100644
--- a/src/doc/unstable-book/src/language-features/asm-goto.md
+++ b/src/doc/unstable-book/src/language-features/asm-goto.md
@@ -21,7 +21,9 @@ unsafe {
 }
 ```
 
-The block must have unit type or diverge.
+The block must have unit type or diverge. The block starts a new safety context,
+so despite outer `unsafe`, you need extra unsafe to perform unsafe operations
+within `label <block>`.
 
 When `label <block>` is used together with `noreturn` option, it means that the
 assembly will not fallthrough. It's allowed to jump to a label within the
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 31e4e79c00a..3fe567b1c39 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -21,7 +21,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>(
     item_def_id: DefId,
 ) -> Vec<clean::Item> {
     let tcx = cx.tcx;
-    let param_env = tcx.param_env(item_def_id);
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
     let ty = tcx.type_of(item_def_id).instantiate_identity();
 
     let finder = auto_trait::AutoTraitFinder::new(tcx);
@@ -34,7 +34,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>(
                 cx,
                 ty,
                 trait_def_id,
-                param_env,
+                typing_env,
                 item_def_id,
                 &finder,
                 DiscardPositiveImpls::No,
@@ -42,13 +42,13 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>(
         })
         .collect();
     // We are only interested in case the type *doesn't* implement the `Sized` trait.
-    if !ty.is_sized(tcx, param_env)
+    if !ty.is_sized(tcx, typing_env)
         && let Some(sized_trait_def_id) = tcx.lang_items().sized_trait()
         && let Some(impl_item) = synthesize_auto_trait_impl(
             cx,
             ty,
             sized_trait_def_id,
-            param_env,
+            typing_env,
             item_def_id,
             &finder,
             DiscardPositiveImpls::Yes,
@@ -64,7 +64,7 @@ fn synthesize_auto_trait_impl<'tcx>(
     cx: &mut DocContext<'tcx>,
     ty: Ty<'tcx>,
     trait_def_id: DefId,
-    param_env: ty::ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     item_def_id: DefId,
     finder: &auto_trait::AutoTraitFinder<'tcx>,
     discard_positive_impls: DiscardPositiveImpls,
@@ -76,7 +76,7 @@ fn synthesize_auto_trait_impl<'tcx>(
         return None;
     }
 
-    let result = finder.find_auto_trait_generics(ty, param_env, trait_def_id, |info| {
+    let result = finder.find_auto_trait_generics(ty, typing_env, trait_def_id, |info| {
         clean_param_env(cx, item_def_id, info.full_user_env, info.region_data, info.vid_to_region)
     });
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9e11360cab4..031696d445d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -42,7 +42,8 @@ use rustc_errors::{FatalError, struct_span_code_err};
 use rustc_hir::PredicateOrigin;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
-use rustc_hir_analysis::lower_ty;
+use rustc_hir_analysis::hir_ty_lowering::FeedConstTy;
+use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty};
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
 use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
@@ -435,10 +436,10 @@ fn clean_middle_term<'tcx>(
 fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
     match term {
         hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
-        hir::Term::Const(c) => Term::Constant(clean_middle_const(
-            ty::Binder::dummy(ty::Const::from_const_arg(cx.tcx, c, ty::FeedConstTy::No)),
-            cx,
-        )),
+        hir::Term::Const(c) => {
+            let ct = lower_const_arg_for_rustdoc(cx.tcx, c, FeedConstTy::No);
+            Term::Constant(clean_middle_const(ty::Binder::dummy(ct), cx))
+        }
     }
 }
 
@@ -625,7 +626,7 @@ fn clean_generic_param<'tcx>(
             (param.name.ident().name, GenericParamDefKind::Const {
                 ty: Box::new(clean_ty(ty, cx)),
                 default: default.map(|ct| {
-                    Box::new(ty::Const::from_const_arg(cx.tcx, ct, ty::FeedConstTy::No).to_string())
+                    Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string())
                 }),
                 synthetic,
             })
@@ -1813,14 +1814,12 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                     // `const_eval_poly` tries to first substitute generic parameters which
                     // results in an ICE while manually constructing the constant and using `eval`
                     // does nothing for `ConstKind::Param`.
-                    let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No);
+                    let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
                     let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) =
                         const_arg.kind
                     {
-                        // Only anon consts can implicitly capture params.
-                        // FIXME: is this correct behavior?
-                        let param_env = cx.tcx.param_env(*def_id);
-                        cx.tcx.normalize_erasing_regions(param_env, ct)
+                        let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id);
+                        cx.tcx.normalize_erasing_regions(typing_env, ct)
                     } else {
                         ct
                     };
@@ -2039,7 +2038,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             format!("{pat:?}").into_boxed_str(),
         ),
         ty::Array(ty, n) => {
-            let n = cx.tcx.normalize_erasing_regions(cx.param_env, n);
+            let n = cx.tcx.normalize_erasing_regions(cx.typing_env(), n);
             let n = print_const(cx, n);
             Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
         }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index e3a0dbe1a7f..a10a6a92bf5 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -772,8 +772,10 @@ impl Item {
                         .find(|field| {
                             let ty =
                                 field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
-                            tcx.layout_of(tcx.param_env(field.did).and(ty))
-                                .is_ok_and(|layout| !layout.is_1zst())
+                            tcx.layout_of(
+                                ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
+                            )
+                            .is_ok_and(|layout| !layout.is_1zst())
                         })
                         .map_or_else(
                             || adt.all_fields().any(|field| field.vis.is_public()),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index e551e0170c6..d59b4e4081c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -419,7 +419,10 @@ fn print_const_with_custom_print_scalar<'tcx>(
         }
         (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
             let ty = ct.ty();
-            let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
+            let size = tcx
+                .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
+                .unwrap()
+                .size;
             let sign_extended_data = int.assert_scalar_int().to_int(size);
             let mut output = if with_underscores {
                 format_integer_with_underscore_sep(&sign_extended_data.to_string())
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index d5f6bfe415d..a562a9eee71 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -19,7 +19,7 @@ use rustc_hir::{HirId, Path};
 use rustc_interface::interface;
 use rustc_lint::{MissingDoc, late_lint_mod};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks};
 pub(crate) use rustc_session::config::{Options, UnstableOptions};
 use rustc_session::{Session, lint};
@@ -88,6 +88,13 @@ impl<'tcx> DocContext<'tcx> {
         ret
     }
 
+    pub(crate) fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv {
+            typing_mode: ty::TypingMode::non_body_analysis(),
+            param_env: self.param_env,
+        }
+    }
+
     /// Call the closure with the given parameters set as
     /// the generic parameters for a type alias' RHS.
     pub(crate) fn enter_alias<F, R>(
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 4def80764ea..29f6f92a6b2 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -861,10 +861,9 @@ impl<'src> Classifier<'src> {
                 },
                 Some(c) => c,
             },
-            TokenKind::RawIdent
-            | TokenKind::UnknownPrefix
-            | TokenKind::InvalidPrefix
-            | TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)),
+            TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
+                Class::Ident(self.new_span(before, text))
+            }
             TokenKind::Lifetime { .. }
             | TokenKind::RawLifetime
             | TokenKind::UnknownPrefixLifetime => Class::Lifetime,
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index b314b060368..d4cca562d6c 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -36,7 +36,7 @@ pub(crate) enum LinkFromSrc {
 /// It returns the `krate`, the source code files and the `span` correspondence map.
 ///
 /// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't
-/// need the `span` context later on, only their position, so instead of keep a whole `Span`, we
+/// need the `span` context later on, only their position, so instead of keeping a whole `Span`, we
 /// only keep the `lo` and `hi`.
 pub(crate) fn collect_spans_and_sources(
     tcx: TyCtxt<'_>,
@@ -45,9 +45,9 @@ pub(crate) fn collect_spans_and_sources(
     include_sources: bool,
     generate_link_to_definition: bool,
 ) -> (FxIndexMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
-    let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
-
     if include_sources {
+        let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
+
         if generate_link_to_definition {
             tcx.hir().walk_toplevel_module(&mut visitor);
         }
@@ -76,7 +76,22 @@ impl<'tcx> SpanMapVisitor<'tcx> {
                 } else {
                     LinkFromSrc::External(def_id)
                 };
-                self.matches.insert(path.span, link);
+                // In case the path ends with generics, we remove them from the span.
+                let span = path
+                    .segments
+                    .last()
+                    .map(|last| {
+                        // In `use` statements, the included item is not in the path segments.
+                        // However, it doesn't matter because you can't have generics on `use`
+                        // statements.
+                        if path.span.contains(last.ident.span) {
+                            path.span.with_hi(last.ident.span.hi())
+                        } else {
+                            path.span
+                        }
+                    })
+                    .unwrap_or(path.span);
+                self.matches.insert(span, link);
             }
             Res::Local(_) => {
                 if let Some(span) = self.tcx.hir().res_span(path.res) {
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index d85ba3a2b14..9317844956d 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -37,9 +37,9 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
         }
 
         let tcx = cx.tcx();
-        let param_env = tcx.param_env(ty_def_id);
+        let typing_env = ty::TypingEnv::post_analysis(tcx, ty_def_id);
         let ty = tcx.type_of(ty_def_id).instantiate_identity();
-        let type_layout = tcx.layout_of(param_env.and(ty));
+        let type_layout = tcx.layout_of(typing_env.as_query_input(ty));
 
         let variants = if let Ok(type_layout) = type_layout
             && let Variants::Multiple { variants, tag, tag_encoding, .. } =
@@ -71,7 +71,7 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
             Vec::new()
         };
 
-        let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
+        let type_layout_size = tcx.layout_of(typing_env.as_query_input(ty)).map(|layout| {
             let is_unsized = layout.is_unsized();
             let is_uninhabited = layout.is_uninhabited();
             let size = layout.size.bytes();
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 6d118ae5784..9e5cf497211 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -692,8 +692,6 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
     const quadcolon = /::\s*::/.exec(path);
     if (path.startsWith("::")) {
         throw ["Paths cannot start with ", "::"];
-    } else if (path.endsWith("::")) {
-        throw ["Paths cannot end with ", "::"];
     } else if (quadcolon !== null) {
         throw ["Unexpected ", quadcolon[0]];
     }
@@ -990,6 +988,12 @@ class VlqHexDecoder {
 }
 class RoaringBitmap {
     constructor(str) {
+        // https://github.com/RoaringBitmap/RoaringFormatSpec
+        //
+        // Roaring bitmaps are used for flags that can be kept in their
+        // compressed form, even when loaded into memory. This decoder
+        // turns the containers into objects, but uses byte array
+        // slices of the original format for the data payload.
         const strdecoded = atob(str);
         const u8array = new Uint8Array(strdecoded.length);
         for (let j = 0; j < strdecoded.length; ++j) {
@@ -1055,9 +1059,24 @@ class RoaringBitmap {
     contains(keyvalue) {
         const key = keyvalue >> 16;
         const value = keyvalue & 0xFFFF;
-        for (let i = 0; i < this.keys.length; ++i) {
-            if (this.keys[i] === key) {
-                return this.containers[i].contains(value);
+        // Binary search algorithm copied from
+        // https://en.wikipedia.org/wiki/Binary_search#Procedure
+        //
+        // Format is required by specification to be sorted.
+        // Because keys are 16 bits and unique, length can't be
+        // bigger than 2**16, and because we have 32 bits of safe int,
+        // left + right can't overflow.
+        let left = 0;
+        let right = this.keys.length - 1;
+        while (left <= right) {
+            const mid = Math.floor((left + right) / 2);
+            const x = this.keys[mid];
+            if (x < key) {
+                left = mid + 1;
+            } else if (x > key) {
+                right = mid - 1;
+            } else {
+                return this.containers[mid].contains(value);
             }
         }
         return false;
@@ -1070,11 +1089,23 @@ class RoaringBitmapRun {
         this.array = array;
     }
     contains(value) {
-        const l = this.runcount * 4;
-        for (let i = 0; i < l; i += 4) {
+        // Binary search algorithm copied from
+        // https://en.wikipedia.org/wiki/Binary_search#Procedure
+        //
+        // Since runcount is stored as 16 bits, left + right
+        // can't overflow.
+        let left = 0;
+        let right = this.runcount - 1;
+        while (left <= right) {
+            const mid = Math.floor((left + right) / 2);
+            const i = mid * 4;
             const start = this.array[i] | (this.array[i + 1] << 8);
             const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8);
-            if (value >= start && value <= (start + lenm1)) {
+            if ((start + lenm1) < value) {
+                left = mid + 1;
+            } else if (start > value) {
+                right = mid - 1;
+            } else {
                 return true;
             }
         }
@@ -1087,10 +1118,22 @@ class RoaringBitmapArray {
         this.array = array;
     }
     contains(value) {
-        const l = this.cardinality * 2;
-        for (let i = 0; i < l; i += 2) {
-            const start = this.array[i] | (this.array[i + 1] << 8);
-            if (value === start) {
+        // Binary search algorithm copied from
+        // https://en.wikipedia.org/wiki/Binary_search#Procedure
+        //
+        // Since cardinality can't be higher than 4096, left + right
+        // cannot overflow.
+        let left = 0;
+        let right = this.cardinality - 1;
+        while (left <= right) {
+            const mid = Math.floor((left + right) / 2);
+            const i = mid * 2;
+            const x = this.array[i] | (this.array[i + 1] << 8);
+            if (x < value) {
+                left = mid + 1;
+            } else if (x > value) {
+                right = mid - 1;
+            } else {
                 return true;
             }
         }
@@ -3974,18 +4017,19 @@ class DocSearch {
 
             if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
                 const elem = parsedQuery.elems[0];
-                for (const id of this.nameTrie.search(elem.normalizedPathLast, this.tailTable)) {
+                // use arrow functions to preserve `this`.
+                const handleNameSearch = id => {
                     const row = this.searchIndex[id];
                     if (!typePassesFilter(elem.typeFilter, row.ty) ||
                         (filterCrates !== null && row.crate !== filterCrates)) {
-                        continue;
+                        return;
                     }
 
                     let pathDist = 0;
                     if (elem.fullPath.length > 1) {
                         pathDist = checkPath(elem.pathWithoutLast, row);
                         if (pathDist === null) {
-                            continue;
+                            return;
                         }
                     }
 
@@ -4008,9 +4052,20 @@ class DocSearch {
                             maxEditDistance,
                         );
                     }
+                };
+                if (elem.normalizedPathLast !== "") {
+                    const last = elem.normalizedPathLast;
+                    for (const id of this.nameTrie.search(last, this.tailTable)) {
+                        handleNameSearch(id);
+                    }
                 }
                 const length = this.searchIndex.length;
+
                 for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
+                    // queries that end in :: bypass the trie
+                    if (elem.normalizedPathLast === "") {
+                        handleNameSearch(i);
+                    }
                     const row = this.searchIndex[i];
                     if (filterCrates !== null && row.crate !== filterCrates) {
                         continue;
diff --git a/src/llvm-project b/src/llvm-project
-Subproject b35599be758613448201a49f4b8c7ebfba5558a
+Subproject 104d0d16c3c7c3fef2435fef6efb2d57b70fff7
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 4a2d8dc636445b276288543882e076f254b3ae9
+Subproject 66221abdeca2002d318fde6efff516aab091df0
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 0b82c0cd04c..00626a37ef8 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
                 },
                 _ => return,
             }
-            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args)
+            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_id, fn_gen_args)
             // TODO: This check currently bails if the local variable has no initializer.
             // That is overly conservative - the lint should fire even if there was no initializer,
             // but the variable has been initialized before `lhs` was evaluated.
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 7d89195eeca..adac2f27ea8 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -62,7 +62,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
         })
         .is_some_and(|assoc_item| {
             let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
-            let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
+            let nty = cx.tcx.normalize_erasing_regions(cx.typing_env(), proj);
 
             nty.is_bool()
         })
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 86c5f6b9f0b..46d67e615c7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -39,7 +39,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
             (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
         // The `U` in `pointer::cast` have to be `Sized`
         // as explained here: https://github.com/rust-lang/rust/issues/60602.
-        && to_pointee_ty.is_sized(cx.tcx, cx.param_env)
+        && to_pointee_ty.is_sized(cx.tcx, cx.typing_env())
     {
         let mut app = Applicability::MachineApplicable;
         let turbofish = match &cast_to_hir_ty.kind {
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index b167d7f2208..fce7f9985ea 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -15,9 +15,10 @@ use rustc_hir::{
     self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat,
     PatKind, Path, QPath, TyKind, UnOp,
 };
+use rustc_hir::def_id::DefId;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
@@ -753,10 +754,10 @@ impl TyCoercionStability {
     fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self {
         match ty {
             DefinedTy::Hir(ty) => Self::for_hir_ty(ty),
-            DefinedTy::Mir(ty) => Self::for_mir_ty(
+            DefinedTy::Mir { def_site_def_id, ty } => Self::for_mir_ty(
                 cx.tcx,
-                ty.param_env,
-                cx.tcx.instantiate_bound_regions_with_erased(ty.value),
+                def_site_def_id,
+                cx.tcx.instantiate_bound_regions_with_erased(ty),
                 for_return,
             ),
         }
@@ -823,12 +824,15 @@ impl TyCoercionStability {
         }
     }
 
-    fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self {
+    fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option<DefId>, ty: Ty<'tcx>, for_return: bool) -> Self {
         let ty::Ref(_, mut ty, _) = *ty.kind() else {
             return Self::None;
         };
 
-        ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+        if let Some(def_id) = def_site_def_id {
+            let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
+            ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        }
         loop {
             break match *ty.kind() {
                 ty::Ref(_, ref_ty, _) => {
@@ -1027,7 +1031,7 @@ fn report<'tcx>(
         State::ExplicitDeref { mutability } => {
             if is_block_like(expr)
                 && let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
-                && ty.is_sized(cx.tcx, cx.param_env)
+                && ty.is_sized(cx.tcx, cx.typing_env())
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 0db6a822ec0..3b6b3c89858 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -454,13 +454,13 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
         && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
         && !has_non_exhaustive_attr(cx.tcx, *adt)
         && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id)
-        && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
+        && let typing_env = typing_env_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
         && let Some(local_def_id) = adt.did().as_local()
         // If all of our fields implement `Eq`, we can implement `Eq` too
         && adt
             .all_fields()
             .map(|f| f.ty(cx.tcx, args))
-            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[]))
+            .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[]))
     {
         span_lint_hir_and_then(
             cx,
@@ -485,7 +485,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De
 }
 
 /// Creates the `ParamEnv` used for the give type's derived `Eq` impl.
-fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv<'_> {
+fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> {
     // Initial map from generic index to param def.
     // Vec<(param_def, needs_eq)>
     let mut params = tcx
@@ -506,7 +506,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         }
     }
 
-    ParamEnv::new(
+    let param_env = ParamEnv::new(
         tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 ClauseKind::Trait(TraitPredicate {
@@ -517,5 +517,9 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
             }),
         )),
         Reveal::UserFacing,
-    )
+    );
+    ty::TypingEnv {
+        typing_mode: ty::TypingMode::non_body_analysis(),
+        param_env,
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 55afdbf22e1..617982f4da3 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
                 sym::mem_forget if is_copy => return,
                 sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => return,
                 sym::mem_drop
-                    if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
+                    if !(arg_ty.needs_drop(cx.tcx, cx.typing_env())
                         || is_must_use_func_call(cx, arg)
                         || is_must_use_ty(cx, arg_ty)
                         || drop_is_single_call_in_arm) =>
@@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
                     (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span))
                 },
                 sym::mem_forget => {
-                    if arg_ty.needs_drop(cx.tcx, cx.param_env) {
+                    if arg_ty.needs_drop(cx.tcx, cx.typing_env()) {
                         (
                             MEM_FORGET,
                             Cow::Owned(format!(
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index c74ba088b78..175d92d2d79 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -198,7 +198,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet)
         // primitive types are never mutable
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
         ty::Adt(adt, args) => {
-            tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
+            tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.typing_env())
                 || matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc))
                     && args.types().any(|ty| is_mutable_ty(cx, ty, tys))
         },
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 25105817ad9..4bc6ad0798c 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -70,7 +70,7 @@ fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDe
             .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(fn_id).instantiate_identity().output());
         let ret_ty = cx
             .tcx
-            .try_normalize_erasing_regions(cx.param_env, ret_ty)
+            .try_normalize_erasing_regions(cx.typing_env(), ret_ty)
             .unwrap_or(ret_ty);
         if cx
             .tcx
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 314d0dfa26c..906da81b183 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -215,7 +215,7 @@ impl {self_ty_without_ref} {{
             && implements_trait(cx, ret_ty, iterator_did, &[])
             && let Some(iter_ty) = make_normalized_projection(
                 cx.tcx,
-                cx.param_env,
+                cx.typing_env(),
                 iterator_did,
                 sym::Item,
                 [ret_ty],
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index c5a2760234f..644365c9fe5 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, ParamEnv};
+use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, Span};
 
@@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
             && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx
-                .try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree()
+                .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree()
             && let element_count = element_count.to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 25f9be8b2d7..593704f206a 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture {
             && let ty = cx.typeck_results().expr_ty(arg)
             && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
             && implements_trait(cx, ty, future_trait_def_id, &[])
-            && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
+            && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty))
             && let size = layout.layout.size()
             && size >= Size::from_bytes(self.future_size_threshold)
         {
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
index d2bdf194ada..5ed948c02bb 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
@@ -150,11 +150,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
         }
 
         let mir = cx.tcx.optimized_mir(def_id);
-        let param_env = cx.tcx.param_env(def_id);
+        let typing_env = mir.typing_env(cx.tcx);
 
         let sizes_of_locals = || {
             mir.local_decls.iter().filter_map(|local| {
-                let layout = cx.tcx.layout_of(param_env.and(local.ty)).ok()?;
+                let layout = cx.tcx.layout_of(typing_env.as_query_input(local.ty)).ok()?;
                 Some((local, layout.size.bytes()))
             })
         };
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 0e488cee6b7..5db28e9ae9b 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                 let has_interior_mutability = !cx
                     .typeck_results()
                     .node_type(canonical_id)
-                    .is_freeze(cx.tcx, cx.param_env);
+                    .is_freeze(cx.tcx, cx.typing_env());
                 if has_interior_mutability {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index ee561ea85ed..d999e1a0585 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -115,11 +115,11 @@ fn is_ref_iterable<'tcx>(
             .tcx
             .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
         && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
-        && let param_env = cx.tcx.param_env(fn_id)
-        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, Some(fn_id), &[])
+        && let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id)
+        && implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[])
         && let Some(into_iter_ty) =
-            make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty])
-        && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty)
+            make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty])
+        && let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty)
         && into_iter_ty == req_res_ty
     {
         let adjustments = typeck.expr_adjustments(self_arg);
@@ -151,7 +151,7 @@ fn is_ref_iterable<'tcx>(
                 // Using by value won't consume anything
                 if implements_trait(cx, self_ty, trait_id, &[])
                     && let Some(ty) =
-                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
+                        make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
                     && ty == res_ty
                 {
                     return Some((AdjustKind::None, self_ty));
@@ -168,7 +168,7 @@ fn is_ref_iterable<'tcx>(
                 };
                 if implements_trait(cx, self_ty, trait_id, &[])
                     && let Some(ty) =
-                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
+                        make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
                     && ty == res_ty
                 {
                     return Some((AdjustKind::reborrow(mutbl), self_ty));
@@ -181,7 +181,7 @@ fn is_ref_iterable<'tcx>(
             // Attempt to borrow
             let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl);
             if implements_trait(cx, self_ty, trait_id, &[])
-                && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
+                && let Some(ty) = make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
                 && ty == res_ty
             {
                 return Some((AdjustKind::borrow(mutbl), self_ty));
@@ -204,7 +204,7 @@ fn is_ref_iterable<'tcx>(
                     && target != self_ty
                     && implements_trait(cx, target, trait_id, &[])
                     && let Some(ty) =
-                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
+                        make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target])
                     && ty == res_ty
                 {
                     Some((AdjustKind::auto_reborrow(mutbl), target))
@@ -222,7 +222,7 @@ fn is_ref_iterable<'tcx>(
                 if is_copy(cx, target)
                     && implements_trait(cx, target, trait_id, &[])
                     && let Some(ty) =
-                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
+                        make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target])
                     && ty == res_ty
                 {
                     Some((AdjustKind::Deref, target))
@@ -240,7 +240,7 @@ fn is_ref_iterable<'tcx>(
                 if self_ty.is_ref()
                     && implements_trait(cx, target, trait_id, &[])
                     && let Some(ty) =
-                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
+                        make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target])
                     && ty == res_ty
                 {
                     Some((AdjustKind::auto_borrow(mutbl), target))
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index 223b0630bfd..7aa13d8d5b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -148,7 +148,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                                 _ => {},
                             }
                         }
-                        requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
+                        requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env());
                         break;
                     }
                 },
@@ -158,9 +158,9 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
         }
 
         if can_lint
-            && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env))
+            && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()))
             // This case could be handled, but a fair bit of care would need to be taken.
-            && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env))
+            && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env()))
         {
             if requires_deref {
                 edits.push((param.span.shrink_to_lo(), "&".into()));
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 9c41528e647..c00b9b368c4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -203,10 +203,10 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
 fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
     if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
         && let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
-        && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, sym::Item, [iter_ty])
+        && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.typing_env(), iter_trait, sym::Item, [iter_ty])
         && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty])
         && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
-            cx.param_env,
+            cx.typing_env(),
             Ty::new_projection_from_args(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args),
         )
     {
@@ -237,7 +237,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
         )
         && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
         && let proj_ty = Ty::new_projection_from_args(cx.tcx, iter_item.def_id, args)
-        && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
+        && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), proj_ty)
     {
         item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id))
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
index 062d1348555..7d01bdc2269 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
 ) {
     let typeck_results = cx.typeck_results();
-    let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results);
+    let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck_results);
     if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id)
         && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id))
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 82549413fa9..84ea3554a35 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -578,7 +578,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                         if output_ty.contains(param_ty) {
                             if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions(
                                 new_subst,
-                                cx.param_env,
+                                cx.typing_env(),
                                 bound_fn_sig.rebind(output_ty),
                             ) {
                                 expr = parent_expr;
diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
index d33021c2a7b..102fa7bc895 100644
--- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
@@ -7,7 +7,7 @@ use super::ZST_OFFSET;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if let ty::RawPtr(ty, _) = cx.typeck_results().expr_ty(recv).kind()
-        && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty))
+        && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(*ty))
         && layout.is_zst()
     {
         span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 6cddd7ea813..e2ab5e98504 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -80,7 +80,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
                     "generally you want to avoid `&mut &mut _` if possible",
                 );
             } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
-                if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) {
+                if ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) {
                     span_lint_hir(
                         self.cx,
                         MUT_MUT,
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index c1424b9f1dc..9ebef531bc5 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
             && use_cx.same_ctxt
             && !use_cx.is_ty_unified
             && let use_node = use_cx.use_node(cx)
-            && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx)
-            && let ty::Param(ty) = *ty.value.skip_binder().kind()
+            && let Some(DefinedTy::Mir { def_site_def_id: _, ty }) = use_node.defined_ty(cx)
+            && let ty::Param(param_ty) = *ty.skip_binder().kind()
             && let Some((hir_id, fn_id, i)) = match use_node {
                 ExprUseNode::MethodArg(_, _, 0) => None,
                 ExprUseNode::MethodArg(hir_id, None, i) => cx
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
                 fn_id,
                 cx.typeck_results().node_args(hir_id),
                 i,
-                ty,
+                param_ty,
                 expr,
                 &self.msrv,
             )
@@ -421,7 +421,7 @@ fn replace_types<'tcx>(
                         .expect_ty(cx.tcx)
                         .to_ty(cx.tcx);
 
-                    if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
+                    if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), projection)
                         && args[term_param_ty.index as usize] != GenericArg::from(projected_ty)
                     {
                         deque.push_back((*term_param_ty, projected_ty));
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 0775d7abdbb..b65ec8c3c48 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -180,11 +180,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
             if !is_self(arg)
                 && !ty.is_mutable_ptr()
                 && !is_copy(cx, ty)
-                && ty.is_sized(cx.tcx, cx.param_env)
+                && ty.is_sized(cx.tcx, cx.typing_env())
                 && !allowed_traits.iter().any(|&t| {
-                    implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::<
-                        ty::GenericArg<'tcx>,
-                    >::None])
+                    implements_trait_with_env_from_iter(
+                        cx.tcx,
+                        cx.typing_env(),
+                        ty, 
+                        t,
+                        None,
+                        [None::<ty::GenericArg<'tcx>>]
+                    )
                 })
                 && !implements_borrow_trait
                 && !all_borrowable_trait
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 5e20b406426..5416e00fe0c 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -270,31 +270,31 @@ impl<'tcx> NonCopyConst<'tcx> {
             instance,
             promoted: None,
         };
-        let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
-        let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP);
+        let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id);
+        let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP);
         Self::is_value_unfrozen_raw(cx, result, ty)
     }
 
     fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
         let args = cx.typeck_results().node_args(hir_id);
 
-        let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), DUMMY_SP);
+        let result = Self::const_eval_resolve(cx.tcx, cx.typing_env(), ty::UnevaluatedConst::new(def_id, args), DUMMY_SP);
         Self::is_value_unfrozen_raw(cx, result, ty)
     }
 
     pub fn const_eval_resolve(
         tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
         ct: ty::UnevaluatedConst<'tcx>,
         span: Span,
     ) -> EvalToValTreeResult<'tcx> {
-        match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) {
+        match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) {
             Ok(Some(instance)) => {
                 let cid = GlobalId {
                     instance,
                     promoted: None,
                 };
-                tcx.const_eval_global_id_for_typeck(param_env, cid, span)
+                tcx.const_eval_global_id_for_typeck(typing_env, cid, span)
             },
             Ok(None) => Err(ErrorHandled::TooGeneric(span)),
             Err(err) => Err(ErrorHandled::Reported(err.into(), span)),
@@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
 
             // Normalize assoc types because ones originated from generic params
             // bounded other traits could have their bound.
-            let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+            let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
             if self.interior_mut.is_interior_mut_ty(cx, normalized)
                 // When there's no default value, lint it only according to its type;
                 // in other words, lint consts whose value *could* be unfrozen, not definitely is.
@@ -361,12 +361,12 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
                             .trait_item_def_id
                         && cx
                             .tcx
-                            .layout_of(cx.tcx.param_env(of_trait_def_id).and(
+                            .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input(
                                 // Normalize assoc types because ones originated from generic params
                                 // bounded other traits could have their bound at the trait defs;
                                 // and, in that case, the definition is *not* generic.
                                 cx.tcx.normalize_erasing_regions(
-                                    cx.tcx.param_env(of_trait_def_id),
+                                    ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id),
                                     cx.tcx.type_of(of_assoc_item).instantiate_identity(),
                                 ),
                             ))
@@ -376,7 +376,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
                             // similar to unknown layouts.
                             // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
                         && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity()
-                        && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty)
+                        && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty)
                         && self.interior_mut.is_interior_mut_ty(cx, normalized)
                         && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
                     {
@@ -386,7 +386,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
                 ItemKind::Impl(Impl { of_trait: None, .. }) => {
                     let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
                     // Normalize assoc types originated from generic params.
-                    let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+                    let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
 
                     if self.interior_mut.is_interior_mut_ty(cx, normalized)
                         && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
index 5d94cfab3b0..1a0bfd8b997 100644
--- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -26,7 +26,7 @@ fn comparison_to_const<'tcx>(
     if let ExprKind::Binary(operator, left, right) = expr.kind
         && let Ok(cmp_op) = CmpOp::try_from(operator.node)
     {
-        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
+        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck);
         match (ecx.eval(left), ecx.eval(right)) {
             (Some(_), Some(_)) => None,
             (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
index 24bfe2b050b..e3fc8d8fea7 100644
--- a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
@@ -39,7 +39,7 @@ fn check_op<'tcx>(
     other: &Expr<'tcx>,
     parent: &Expr<'tcx>,
 ) {
-    if ConstEvalCtxt::with_env(cx.tcx, cx.param_env, tck).eval_simple(op) == Some(Constant::Int(0)) {
+    if ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), tck).eval_simple(op) == Some(Constant::Int(0)) {
         if different_types(tck, other, parent) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index ab5f91c1d67..8272d3643d4 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -17,8 +17,7 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) {
-        let typeck = cx.typeck_results();
-        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
+        let ecx = ConstEvalCtxt::new(cx);
         let left_is_local = match ecx.eval_with_source(left) {
             Some((c, s)) if !is_allowed(&c) => s.is_local(),
             Some(_) => return,
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index a00fd01a62e..f69cb9be4ca 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -251,7 +251,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
     {
         let mut applicability = Applicability::MachineApplicable;
         let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
-        let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
+        let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env())
             && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
         let sugg = if let Some(else_inner) = r#else {
             if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index dc66fb28fa8..0ac818c21d9 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 });
             } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                 if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
-                    cx.param_env,
+                    cx.typing_env(),
                     Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
                 ) {
                     if deref_ty == expr_ty {
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 1e0f6dff1ab..aeff31d02d2 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -391,7 +391,7 @@ fn check_final_expr<'tcx>(
 
             if let Some(inner) = inner {
                 if for_each_unconsumed_temporary(cx, inner, |temporary_ty| {
-                    if temporary_ty.has_significant_drop(cx.tcx, cx.param_env)
+                    if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env())
                         && temporary_ty
                             .walk()
                             .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static()))
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index abd8363456d..1a5b958e6a6 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -154,7 +154,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
         let ty = self
             .cx
             .tcx
-            .try_normalize_erasing_regions(self.cx.param_env, ty)
+            .try_normalize_erasing_regions(self.cx.typing_env(), ty)
             .unwrap_or(ty);
         match self.type_cache.entry(ty) {
             Entry::Occupied(e) => return *e.get(),
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 52bb7c4bd68..50a1577b288 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -58,7 +58,7 @@ fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item:
         && let Some(last_field) = data.fields().last()
         && let field_ty = cx
             .tcx
-            .normalize_erasing_regions(cx.param_env, cx.tcx.type_of(last_field.def_id).instantiate_identity())
+            .normalize_erasing_regions(cx.typing_env(), cx.tcx.type_of(last_field.def_id).instantiate_identity())
         && let ty::Array(_, array_len) = *field_ty.kind()
         && let Some(0) = array_len.try_to_target_usize(cx.tcx)
     {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
index ca9daf2d2a0..1209bd5b34f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -88,8 +88,8 @@ pub(super) fn check<'tcx>(
         && is_normalizable(cx, cx.param_env, to_ty)
         // we only want to lint if the target type has a niche that is larger than the one of the source type
         // e.g. `u8` to `NonZero<u8>` should lint, but `NonZero<u8>` to `u8` should not
-        && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty))
-        && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty))
+        && let Ok(from_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(from_ty))
+        && let Ok(to_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(to_ty))
         && match (from_layout.largest_niche, to_layout.largest_niche) {
             (Some(from_niche), Some(to_niche)) => !range_fully_contained(from_niche.valid_range, to_niche.valid_range),
             (None, Some(_)) => true,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
index 0772b284968..bf6700b1b6b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
                         if from_mutbl == to_mutbl
-                            && to_pointee_ty.is_sized(cx.tcx, cx.param_env)
+                            && to_pointee_ty.is_sized(cx.tcx, cx.typing_env())
                             && msrv.meets(msrvs::POINTER_CAST)
                         {
                             diag.span_suggestion_verbose(
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 3b32e4396b9..48d65eb15d9 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -206,12 +206,12 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T
                 continue;
             },
             (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)), _)
-                if !unsized_ty.is_sized(cx.tcx, cx.param_env) =>
+                if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) =>
             {
                 (true, false)
             },
             (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)))
-                if !unsized_ty.is_sized(cx.tcx, cx.param_env) =>
+                if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) =>
             {
                 (false, true)
             },
@@ -244,7 +244,7 @@ enum ReducedTy<'tcx> {
 /// Reduce structs containing a single non-zero sized field to it's contained type.
 fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> {
     loop {
-        ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
+        ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty);
         return match *ty.kind() {
             ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
                 ReducedTy::TypeErasure { raw_ptr_only: false }
@@ -297,8 +297,8 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
 }
 
 fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty)
-        && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
+    if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty)
+        && let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty))
     {
         layout.layout.size().bytes() == 0
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index e8ccd35b4da..5baa67b1f3e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -4,10 +4,11 @@ use rustc_middle::ty::Ty;
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
 pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
-    if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from)
-        && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to)
-        && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from))
-        && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to))
+    let typing_env = cx.typing_env();
+    if let Ok(from) = cx.tcx.try_normalize_erasing_regions(typing_env, from)
+        && let Ok(to) = cx.tcx.try_normalize_erasing_regions(typing_env, to)
+        && let Ok(from_layout) = cx.tcx.layout_of(typing_env.as_query_input(from))
+        && let Ok(to_layout) = cx.tcx.layout_of(typing_env.as_query_input(to))
     {
         from_layout.size != to_layout.size || from_layout.align.abi != to_layout.align.abi
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index 1a656088b17..de3456a8ba5 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath:
             // here because `mod.rs` guarantees this lint is only run on types outside of bodies and
             // is not run on locals.
             let ty = lower_ty(cx.tcx, hir_ty);
-            if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) {
+            if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.typing_env()) {
                 return false;
             }
             hir_ty.span
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 230239335c6..9b236d3bda5 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
             && let boxed_alloc_ty = last.args.get(1)
             && let ty_ty = lower_ty(cx.tcx, boxed_ty)
             && !ty_ty.has_escaping_bound_vars()
-            && ty_ty.is_sized(cx.tcx, cx.param_env)
+            && ty_ty.is_sized(cx.tcx, cx.typing_env())
             && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
             && ty_ty_size < box_size_threshold
             // https://github.com/rust-lang/rust-clippy/issues/7114
diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
index cfa565cf803..ee9ef017253 100644
--- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
+++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
@@ -46,7 +46,7 @@ impl LateLintPass<'_> for UninhabitedReferences {
 
         if let ExprKind::Unary(UnOp::Deref, _) = expr.kind {
             let ty = cx.typeck_results().expr_ty_adjusted(expr);
-            if ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
+            if ty.is_privately_uninhabited(cx.tcx, cx.typing_env()) {
                 span_lint(
                     cx,
                     UNINHABITED_REFERENCES,
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for UninhabitedReferences {
         }
         if let FnRetTy::Return(hir_ty) = fndecl.output
             && let TyKind::Ref(_, mut_ty) = hir_ty.kind
-            && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
+            && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.typing_env())
         {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index 14f4aa6676b..34df1d5560a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -82,7 +82,7 @@ impl UnnecessaryBoxReturns {
         // It's sometimes useful to return Box<T> if T is unsized, so don't lint those.
         // Also, don't lint if we know that T is very large, in which case returning
         // a Box<T> may be beneficial.
-        if boxed_ty.is_sized(cx.tcx, cx.param_env) && approx_ty_size(cx, boxed_ty) <= self.maximum_size {
+        if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size {
             span_lint_and_then(
                 cx,
                 UNNECESSARY_BOX_RETURNS,
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 24a02c7ef87..52c98646289 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -18,7 +18,7 @@ use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::ConstValue;
 use rustc_middle::mir::interpret::{Scalar, alloc_range};
-use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy};
+use rustc_middle::ty::{self, FloatTy, IntTy, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::Ident;
@@ -387,7 +387,7 @@ impl Ord for FullInt {
 /// See the module level documentation for some context.
 pub struct ConstEvalCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     typeck: &'tcx TypeckResults<'tcx>,
     source: Cell<ConstantSource>,
 }
@@ -398,17 +398,17 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
     pub fn new(cx: &LateContext<'tcx>) -> Self {
         Self {
             tcx: cx.tcx,
-            param_env: cx.param_env,
+            typing_env: cx.typing_env(),
             typeck: cx.typeck_results(),
             source: Cell::new(ConstantSource::Local),
         }
     }
 
     /// Creates an evaluation context.
-    pub fn with_env(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self {
+    pub fn with_env(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self {
         Self {
             tcx,
-            param_env,
+            typing_env,
             typeck,
             source: Cell::new(ConstantSource::Local),
         }
@@ -643,7 +643,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 let args = self.typeck.node_args(id);
                 let result = self
                     .tcx
-                    .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
+                    .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
                     .ok()
                     .map(|val| mir::Const::from_value(val, ty))?;
                 f(self, result)
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index a2e97919d04..7f0363ac942 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -105,7 +105,7 @@ fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> boo
     {
         cx.typeck_results()
             .expr_ty(e)
-            .has_significant_drop(cx.tcx, cx.param_env)
+            .has_significant_drop(cx.tcx, cx.typing_env())
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index c73ab4bfa68..ea866a78d87 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -297,8 +297,8 @@ impl HirEqInterExpr<'_, '_, '_> {
         if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
             && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
             && let (Some(l), Some(r)) = (
-                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_lhs).eval_simple(left),
-                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_rhs).eval_simple(right),
+                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.typing_env(), typeck_lhs).eval_simple(left),
+                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.typing_env(), typeck_rhs).eval_simple(right),
             )
             && l == r
         {
@@ -813,7 +813,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     #[expect(clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr<'_>) {
         let simple_const = self.maybe_typeck_results.and_then(|typeck_results| {
-            ConstEvalCtxt::with_env(self.cx.tcx, self.cx.param_env, typeck_results).eval_simple(e)
+            ConstEvalCtxt::with_env(self.cx.tcx, self.cx.typing_env(), typeck_results).eval_simple(e)
         });
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 19316a90683..6408cc938cb 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -116,8 +116,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv,
-    ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy,
+    Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -1631,7 +1631,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
     }
     let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
     if let Some(Constant::Int(v)) =
-        ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(enclosing_body), cx.tcx.typeck(enclosing_body)).eval(e)
+        ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), cx.tcx.typeck(enclosing_body)).eval(e)
     {
         return value == v;
     }
@@ -2712,9 +2712,17 @@ pub fn walk_to_expr_usage<'tcx, T>(
 pub enum DefinedTy<'tcx> {
     // Used for locals and closures defined within the function.
     Hir(&'tcx hir::Ty<'tcx>),
-    /// Used for function signatures, and constant and static values. This includes the `ParamEnv`
-    /// from the definition site.
-    Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>),
+    /// Used for function signatures, and constant and static values. The type is
+    /// in the context of its definition site. We also track the `def_id` of its
+    /// definition site.
+    /// 
+    /// WARNING: As the `ty` in in the scope of the definition, not of the function
+    /// using it, you must be very careful with how you use it. Using it in the wrong
+    /// scope easily results in ICEs. 
+    Mir {
+        def_site_def_id: Option<DefId>,
+        ty: Binder<'tcx, Ty<'tcx>>,
+    },
 }
 
 /// The context an expressions value is used in.
@@ -2833,10 +2841,10 @@ impl<'tcx> ExprUseNode<'tcx> {
     pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
         match *self {
             Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
-            Self::ConstStatic(id) => Some(DefinedTy::Mir(
-                cx.param_env
-                    .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
-            )),
+            Self::ConstStatic(id) => Some(DefinedTy::Mir {
+                def_site_def_id: Some(id.def_id.to_def_id()),
+                ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()),
+        }),
             Self::Return(id) => {
                 if let Node::Expr(Expr {
                     kind: ExprKind::Closure(c),
@@ -2848,9 +2856,8 @@ impl<'tcx> ExprUseNode<'tcx> {
                         FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
                     }
                 } else {
-                    Some(DefinedTy::Mir(
-                        cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()),
-                    ))
+                    let ty = cx.tcx.fn_sig(id).instantiate_identity().output();
+                    Some(DefinedTy::Mir { def_site_def_id: Some(id.def_id.to_def_id()), ty })
                 }
             },
             Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
@@ -2866,12 +2873,9 @@ impl<'tcx> ExprUseNode<'tcx> {
                             .find(|f| f.name == field.ident.name)
                             .map(|f| (adt, f))
                     })
-                    .map(|(adt, field_def)| {
-                        DefinedTy::Mir(
-                            cx.tcx
-                                .param_env(adt.did())
-                                .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())),
-                        )
+                    .map(|(adt, field_def)| DefinedTy::Mir {
+                            def_site_def_id: Some(adt.did()),
+                            ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()),
                     }),
                 _ => None,
             },
@@ -2880,17 +2884,19 @@ impl<'tcx> ExprUseNode<'tcx> {
                 let (hir_ty, ty) = sig.input_with_hir(i)?;
                 Some(match hir_ty {
                     Some(hir_ty) => DefinedTy::Hir(hir_ty),
-                    None => DefinedTy::Mir(
-                        sig.predicates_id()
-                            .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id))
-                            .and(ty),
-                    ),
+                    None => DefinedTy::Mir {
+                        def_site_def_id:  sig.predicates_id(),
+                        ty,
+                    }
                 })
             },
             Self::MethodArg(id, _, i) => {
                 let id = cx.typeck_results().type_dependent_def_id(id)?;
                 let sig = cx.tcx.fn_sig(id).skip_binder();
-                Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
+                Some(DefinedTy::Mir {
+                    def_site_def_id: Some(id),
+                    ty: sig.input(i),
+                })
             },
             Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None,
         }
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 971f8eeb1b3..345c46f944a 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
@@ -142,7 +142,7 @@ fn check_rvalue<'tcx>(
                 // We cannot allow this for now.
                 return Err((span, "unsizing casts are only allowed for references right now".into()));
             };
-            let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, tcx.param_env(def_id));
+            let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, ty::TypingEnv::post_analysis(tcx, def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
                 check_operand(tcx, op, span, body, msrv)?;
                 // Casting/coercing things to slices is fine.
@@ -233,6 +233,7 @@ fn check_statement<'tcx>(
         | StatementKind::PlaceMention(..)
         | StatementKind::Coverage(..)
         | StatementKind::ConstEvalCounter
+        | StatementKind::BackwardIncompatibleDropHint { .. }
         | StatementKind::Nop => Ok(()),
     }
 }
@@ -408,15 +409,17 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             return true;
         }
 
+
+        let (infcx, param_env) =
+            tcx.infer_ctxt().build_with_typing_env(body.typing_env(tcx));
         // FIXME(const_trait_impl) constness
         let obligation = Obligation::new(
             tcx,
             ObligationCause::dummy_with_span(body.span),
-            ConstCx::new(tcx, body).param_env,
+            param_env,
             TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
         );
 
-        let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
         let mut selcx = SelectionContext::new(&infcx);
         let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
             return false;
@@ -434,5 +437,5 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
         ocx.select_all_or_error().is_empty()
     }
 
-    !ty.needs_drop(tcx, ConstCx::new(tcx, body).param_env)
+    !ty.needs_drop(tcx, ConstCx::new(tcx, body).typing_env)
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 770cd9c3786..3498606dfd3 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
     GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, UintTy, Upcast, VariantDef, VariantDiscr,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -38,7 +38,7 @@ pub use type_certainty::expr_type_is_certain;
 
 /// Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
+    ty.is_copy_modulo_regions(cx.tcx, cx.typing_env())
 }
 
 /// This checks whether a given type is known to implement Debug.
@@ -226,7 +226,7 @@ pub fn implements_trait<'tcx>(
     trait_id: DefId,
     args: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, None, args.iter().map(|&x| Some(x)))
+    implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, trait_id, None, args.iter().map(|&x| Some(x)))
 }
 
 /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -235,19 +235,19 @@ pub fn implements_trait<'tcx>(
 /// environment, used for checking const traits.
 pub fn implements_trait_with_env<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
     callee_id: Option<DefId>,
     args: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x)))
+    implements_trait_with_env_from_iter(tcx, typing_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x)))
 }
 
 /// Same as `implements_trait_from_env` but takes the arguments as an iterator.
 pub fn implements_trait_with_env_from_iter<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
     callee_id: Option<DefId>,
@@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         return false;
     }
 
-    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
     let args = args
         .into_iter()
         .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
@@ -467,7 +467,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         if !seen.insert(ty) {
             return false;
         }
-        if !ty.has_significant_drop(cx.tcx, cx.param_env) {
+        if !ty.has_significant_drop(cx.tcx, cx.typing_env()) {
             false
         }
         // Check for std types which implement drop, but only for memory allocation.
@@ -575,8 +575,9 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
 
 /// Checks if a given type looks safe to be uninitialized.
 pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    let typing_env = cx.typing_env().with_reveal_all_normalized(cx.tcx);
     cx.tcx
-        .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty)))
+        .check_validity_requirement((ValidityRequirement::Uninit, typing_env.as_query_input(ty)))
         .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty))
 }
 
@@ -725,7 +726,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                 _ => None,
             }
         },
-        ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
+        ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
             Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
             _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
         },
@@ -1111,12 +1112,12 @@ pub fn make_projection<'tcx>(
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     container_id: DefId,
     assoc_ty: Symbol,
     args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> Option<Ty<'tcx>> {
-    fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
+    fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
         if let Some((i, arg)) = ty
             .args
@@ -1132,7 +1133,7 @@ pub fn make_normalized_projection<'tcx>(
             );
             return None;
         }
-        match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) {
+        match tcx.try_normalize_erasing_regions(typing_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) {
             Ok(ty) => Some(ty),
             Err(e) => {
                 debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
@@ -1140,7 +1141,7 @@ pub fn make_normalized_projection<'tcx>(
             },
         }
     }
-    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
+    helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?)
 }
 
 /// Helper to check if given type has inner mutability such as [`std::cell::Cell`] or
@@ -1238,12 +1239,12 @@ impl<'tcx> InteriorMut<'tcx> {
 
 pub fn make_normalized_projection_with_regions<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
     container_id: DefId,
     assoc_ty: Symbol,
     args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 ) -> Option<Ty<'tcx>> {
-    fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
+    fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
         if let Some((i, arg)) = ty
             .args
@@ -1260,10 +1261,8 @@ pub fn make_normalized_projection_with_regions<'tcx>(
             return None;
         }
         let cause = ObligationCause::dummy();
-        match tcx
-            .infer_ctxt()
-            .build(TypingMode::from_param_env(param_env))
-            .at(&cause, param_env)
+        let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+        match infcx.at(&cause, param_env)
             .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args))
         {
             Ok(ty) => Some(ty.value),
@@ -1273,20 +1272,13 @@ pub fn make_normalized_projection_with_regions<'tcx>(
             },
         }
     }
-    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
+    helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?)
 }
 
-pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     let cause = ObligationCause::dummy();
-    match tcx
-        .infer_ctxt()
-        .build(TypingMode::from_param_env(param_env))
-        .at(&cause, param_env)
-        .query_normalize(ty)
-    {
-        Ok(ty) => ty.value,
-        Err(_) => ty,
-    }
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+    infcx.at(&cause, param_env).query_normalize(ty).map_or(ty, |ty| ty.value)
 }
 
 /// Checks if the type is `core::mem::ManuallyDrop<_>`
@@ -1300,7 +1292,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
         if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
             && implements_trait(cx, ty, deref_did, &[])
         {
-            make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
+            make_normalized_projection(cx.tcx, cx.typing_env(), deref_did, sym::Target, [ty])
         } else {
             None
         }
diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock
index 8dad30df6d1..0c0fe477cdd 100644
--- a/src/tools/miri/miri-script/Cargo.lock
+++ b/src/tools/miri/miri-script/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "anyhow"
@@ -521,15 +521,15 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
 
 [[package]]
 name = "xshell"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
+checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
+checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547"
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 16fcc26be33..a855603eeb3 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -12,7 +12,7 @@ use std::{cmp, mem};
 use rustc_abi::{BackendRepr, Size};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::{Mutability, RetagKind};
-use rustc_middle::ty::layout::HasParamEnv;
+use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty};
 
 use self::diagnostics::{RetagCause, RetagInfo};
@@ -71,7 +71,7 @@ impl NewPermission {
                         access: None,
                         protector: None,
                     }
-                } else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
+                } else if pointee.is_unpin(*cx.tcx, cx.typing_env()) {
                     // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
                     NewPermission::Uniform {
                         perm: Permission::Unique,
@@ -129,7 +129,7 @@ impl NewPermission {
     fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self {
         // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
         let pointee = ty.builtin_deref(true).unwrap();
-        if pointee.is_unpin(*cx.tcx, cx.param_env()) {
+        if pointee.is_unpin(*cx.tcx, cx.typing_env()) {
             // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
             // a weak protector).
             NewPermission::Uniform {
@@ -608,7 +608,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                 match new_perm {
                     NewPermission::Uniform { perm, .. } =>
                         write!(kind_str, "{perm:?} permission").unwrap(),
-                    NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.param_env()) =>
+                    NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env()) =>
                         write!(kind_str, "{freeze_perm:?} permission").unwrap(),
                     NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. }  =>
                         write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(),
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 f92150758dc..8469744bbc4 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{BackendRepr, Size};
 use rustc_middle::mir::{Mutability, RetagKind};
-use rustc_middle::ty::layout::HasParamEnv;
+use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::def_id::DefId;
 
@@ -132,8 +132,8 @@ impl<'tcx> NewPermission {
         kind: RetagKind,
         cx: &crate::MiriInterpCx<'tcx>,
     ) -> Option<Self> {
-        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env());
-        let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env());
+        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
+        let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env());
         let is_protected = kind == RetagKind::FnEntry;
         // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
         // interior mutability and protectors interact poorly.
@@ -164,10 +164,10 @@ impl<'tcx> NewPermission {
         zero_size: bool,
     ) -> Option<Self> {
         let pointee = ty.builtin_deref(true).unwrap();
-        pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| {
+        pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
             // Regular `Unpin` box, give it `noalias` but only a weak protector
             // because it is valid to deallocate it within the function.
-            let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env());
+            let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env());
             let protected = kind == RetagKind::FnEntry;
             let initial_state = Permission::new_reserved(ty_is_freeze, protected);
             Self {
@@ -521,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Note: if we were to inline `new_reserved` below we would find out that
         // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`.
         // We are nevertheless including it here for clarity.
-        let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.param_env());
+        let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
         // Retag it. With protection! That is the entire point.
         let new_perm = NewPermission {
             initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true),
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 1e56e104918..85591a0b370 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -268,10 +268,14 @@ pub fn create_ecx<'tcx>(
     entry_type: EntryFnType,
     config: &MiriConfig,
 ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
-    let param_env = ty::ParamEnv::reveal_all();
-    let layout_cx = LayoutCx::new(tcx, param_env);
-    let mut ecx =
-        InterpCx::new(tcx, rustc_span::DUMMY_SP, param_env, MiriMachine::new(config, layout_cx));
+    let typing_env = ty::TypingEnv::fully_monomorphized();
+    let layout_cx = LayoutCx::new(tcx, typing_env);
+    let mut ecx = InterpCx::new(
+        tcx,
+        rustc_span::DUMMY_SP,
+        typing_env,
+        MiriMachine::new(config, layout_cx)
+    );
 
     // Some parts of initialization require a full `InterpCx`.
     MiriMachine::late_init(&mut ecx, config, {
@@ -376,7 +380,7 @@ pub fn create_ecx<'tcx>(
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
             let start_instance = ty::Instance::try_resolve(
                 tcx,
-                ty::ParamEnv::reveal_all(),
+                typing_env,
                 start_id,
                 tcx.mk_args(&[ty::GenericArg::from(main_ret_ty)]),
             )
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 526030bef2e..4b34f1686a0 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -116,8 +116,8 @@ pub fn resolve_path<'tcx>(
 /// Gets the layout of a type at a path.
 #[track_caller]
 pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
-    let ty =
-        resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all());
+    let ty = resolve_path(cx.tcx(), path, Namespace::TypeNS)
+        .ty(cx.tcx(), cx.typing_env());
     cx.layout_of(ty).to_result().ok().unwrap()
 }
 
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 9668998aaa3..7b03aed4763 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -17,7 +17,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::static_assert_size;
 use rustc_middle::mir;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{
+    HasTyCtxt, HasTypingEnv, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
+};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::config::InliningThreshold;
 use rustc_span::def_id::{CrateNum, DefId};
@@ -1127,7 +1129,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             };
             let info = ecx.get_alloc_info(alloc_id);
             let def_ty = ecx.tcx.type_of(def_id).instantiate_identity();
-            let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
+            let extern_decl_layout =
+                ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap();
             if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align {
                 throw_unsup_format!(
                     "extern static `{link_name}` has been declared as `{krate}::{name}` \
diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout
index 2d7fb5f4a61..6058735f005 100644
--- a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout
+++ b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout
@@ -1,2 +1,2 @@
-The loop took around 1250ms
+The loop took around 1350ms
 (It's fine for this number to change when you `--bless` this test.)
diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs
index f8d1666adda..9dd30713f95 100644
--- a/src/tools/run-make-support/src/external_deps/c_build.rs
+++ b/src/tools/run-make-support/src/external_deps/c_build.rs
@@ -1,7 +1,7 @@
 use std::path::PathBuf;
 
 use crate::artifact_names::{dynamic_lib_name, static_lib_name};
-use crate::external_deps::cc::{cc, cxx};
+use crate::external_deps::c_cxx_compiler::{cc, cxx};
 use crate::external_deps::llvm::llvm_ar;
 use crate::path_helpers::path;
 use crate::targets::{is_darwin, is_msvc, is_windows};
diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs
index 011ad89e170..becb91ae989 100644
--- a/src/tools/run-make-support/src/external_deps/cc.rs
+++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/cc.rs
@@ -1,7 +1,7 @@
 use std::path::Path;
 
 use crate::command::Command;
-use crate::{env_var, is_msvc, is_windows, uname};
+use crate::{env_var, is_msvc};
 
 /// Construct a new platform-specific C compiler invocation.
 ///
@@ -127,99 +127,3 @@ impl Cc {
         self
     }
 }
-
-/// `EXTRACFLAGS`
-pub fn extra_c_flags() -> Vec<&'static str> {
-    // Adapted from tools.mk (trimmed):
-    //
-    // ```makefile
-    // ifdef IS_WINDOWS
-    //     ifdef IS_MSVC
-    //         EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
-    //     else
-    //         EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
-    //     endif
-    // else
-    //     ifeq ($(UNAME),Darwin)
-    //         EXTRACFLAGS := -lresolv
-    //     else
-    //         ifeq ($(UNAME),FreeBSD)
-    //             EXTRACFLAGS := -lm -lpthread -lgcc_s
-    //         else
-    //             ifeq ($(UNAME),SunOS)
-    //                 EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
-    //             else
-    //                 ifeq ($(UNAME),OpenBSD)
-    //                     EXTRACFLAGS := -lm -lpthread -lc++abi
-    //                 else
-    //                     EXTRACFLAGS := -lm -lrt -ldl -lpthread
-    //                 endif
-    //             endif
-    //         endif
-    //     endif
-    // endif
-    // ```
-
-    if is_windows() {
-        if is_msvc() {
-            vec![
-                "ws2_32.lib",
-                "userenv.lib",
-                "advapi32.lib",
-                "bcrypt.lib",
-                "ntdll.lib",
-                "synchronization.lib",
-            ]
-        } else {
-            vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
-        }
-    } else {
-        match uname() {
-            n if n.contains("Darwin") => vec!["-lresolv"],
-            n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
-            n if n.contains("SunOS") => {
-                vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
-            }
-            n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
-            _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
-        }
-    }
-}
-
-/// `EXTRACXXFLAGS`
-pub fn extra_cxx_flags() -> Vec<&'static str> {
-    // Adapted from tools.mk (trimmed):
-    //
-    // ```makefile
-    // ifdef IS_WINDOWS
-    //     ifdef IS_MSVC
-    //     else
-    //         EXTRACXXFLAGS := -lstdc++
-    //     endif
-    // else
-    //     ifeq ($(UNAME),Darwin)
-    //         EXTRACXXFLAGS := -lc++
-    //     else
-    //         ifeq ($(UNAME),FreeBSD)
-    //         else
-    //             ifeq ($(UNAME),SunOS)
-    //             else
-    //                 ifeq ($(UNAME),OpenBSD)
-    //                 else
-    //                     EXTRACXXFLAGS := -lstdc++
-    //                 endif
-    //             endif
-    //         endif
-    //     endif
-    // endif
-    // ```
-    if is_windows() {
-        if is_msvc() { vec![] } else { vec!["-lstdc++"] }
-    } else {
-        match &uname()[..] {
-            "Darwin" => vec!["-lc++"],
-            "FreeBSD" | "SunOS" | "OpenBSD" => vec![],
-            _ => vec!["-lstdc++"],
-        }
-    }
-}
diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs
new file mode 100644
index 00000000000..49210d75e06
--- /dev/null
+++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/extras.rs
@@ -0,0 +1,97 @@
+use crate::{is_msvc, is_windows, uname};
+
+/// `EXTRACFLAGS`
+pub fn extra_c_flags() -> Vec<&'static str> {
+    // Adapted from tools.mk (trimmed):
+    //
+    // ```makefile
+    // ifdef IS_WINDOWS
+    //     ifdef IS_MSVC
+    //         EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
+    //     else
+    //         EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
+    //     endif
+    // else
+    //     ifeq ($(UNAME),Darwin)
+    //         EXTRACFLAGS := -lresolv
+    //     else
+    //         ifeq ($(UNAME),FreeBSD)
+    //             EXTRACFLAGS := -lm -lpthread -lgcc_s
+    //         else
+    //             ifeq ($(UNAME),SunOS)
+    //                 EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
+    //             else
+    //                 ifeq ($(UNAME),OpenBSD)
+    //                     EXTRACFLAGS := -lm -lpthread -lc++abi
+    //                 else
+    //                     EXTRACFLAGS := -lm -lrt -ldl -lpthread
+    //                 endif
+    //             endif
+    //         endif
+    //     endif
+    // endif
+    // ```
+
+    if is_windows() {
+        if is_msvc() {
+            vec![
+                "ws2_32.lib",
+                "userenv.lib",
+                "advapi32.lib",
+                "bcrypt.lib",
+                "ntdll.lib",
+                "synchronization.lib",
+            ]
+        } else {
+            vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
+        }
+    } else {
+        match uname() {
+            n if n.contains("Darwin") => vec!["-lresolv"],
+            n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
+            n if n.contains("SunOS") => {
+                vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
+            }
+            n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
+            _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
+        }
+    }
+}
+
+/// `EXTRACXXFLAGS`
+pub fn extra_cxx_flags() -> Vec<&'static str> {
+    // Adapted from tools.mk (trimmed):
+    //
+    // ```makefile
+    // ifdef IS_WINDOWS
+    //     ifdef IS_MSVC
+    //     else
+    //         EXTRACXXFLAGS := -lstdc++
+    //     endif
+    // else
+    //     ifeq ($(UNAME),Darwin)
+    //         EXTRACXXFLAGS := -lc++
+    //     else
+    //         ifeq ($(UNAME),FreeBSD)
+    //         else
+    //             ifeq ($(UNAME),SunOS)
+    //             else
+    //                 ifeq ($(UNAME),OpenBSD)
+    //                 else
+    //                     EXTRACXXFLAGS := -lstdc++
+    //                 endif
+    //             endif
+    //         endif
+    //     endif
+    // endif
+    // ```
+    if is_windows() {
+        if is_msvc() { vec![] } else { vec!["-lstdc++"] }
+    } else {
+        match &uname()[..] {
+            "Darwin" => vec!["-lc++"],
+            "FreeBSD" | "SunOS" | "OpenBSD" => vec![],
+            _ => vec!["-lstdc++"],
+        }
+    }
+}
diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs
new file mode 100644
index 00000000000..e02c4f97255
--- /dev/null
+++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/gcc.rs
@@ -0,0 +1,66 @@
+use std::path::Path;
+
+use crate::command::Command;
+
+/// Construct a gcc invocation.
+///
+/// WARNING: This assumes *a* `gcc` exists in the environment and is suitable for use.
+#[track_caller]
+pub fn gcc() -> Gcc {
+    Gcc::new()
+}
+
+/// A specific `gcc`.
+#[derive(Debug)]
+#[must_use]
+pub struct Gcc {
+    cmd: Command,
+}
+
+crate::macros::impl_common_helpers!(Gcc);
+
+impl Gcc {
+    /// Construct a `gcc` invocation. This assumes that *a* suitable `gcc` is available in the
+    /// environment.
+    ///
+    /// Note that this does **not** prepopulate the `gcc` invocation with `CC_DEFAULT_FLAGS`.
+    #[track_caller]
+    pub fn new() -> Self {
+        let cmd = Command::new("gcc");
+        Self { cmd }
+    }
+
+    /// Specify path of the input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
+    /// Adds directories to the list that the linker searches for libraries.
+    /// Equivalent to `-L`.
+    pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg("-L");
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
+    /// Specify `-o`.
+    pub fn out_exe(&mut self, name: &str) -> &mut Self {
+        self.cmd.arg("-o");
+        self.cmd.arg(name);
+        self
+    }
+
+    /// Specify path of the output binary.
+    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg("-o");
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
+    /// Optimize the output at `-O3`.
+    pub fn optimize(&mut self) -> &mut Self {
+        self.cmd.arg("-O3");
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs
new file mode 100644
index 00000000000..9aaefd8aa47
--- /dev/null
+++ b/src/tools/run-make-support/src/external_deps/c_cxx_compiler/mod.rs
@@ -0,0 +1,7 @@
+mod cc;
+mod extras;
+mod gcc;
+
+pub use cc::*;
+pub use extras::*;
+pub use gcc::*;
diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs
index 80c34a9070f..129b06761ef 100644
--- a/src/tools/run-make-support/src/external_deps/mod.rs
+++ b/src/tools/run-make-support/src/external_deps/mod.rs
@@ -2,8 +2,8 @@
 //! such as `cc` or `python`.
 
 pub mod c_build;
+pub mod c_cxx_compiler;
 pub mod cargo;
-pub mod cc;
 pub mod clang;
 pub mod htmldocck;
 pub mod llvm;
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 6cf0aedfe9f..819bbc161e6 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -46,10 +46,10 @@ pub use wasmparser;
 // tidy-alphabetical-end
 
 // Re-exports of external dependencies.
-pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc};
+pub use external_deps::{c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc};
 
 // These rely on external dependencies.
-pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
+pub use c_cxx_compiler::{Cc, Gcc, cc, cxx, extra_c_flags, extra_cxx_flags, gcc};
 pub use c_build::{
     build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
     build_native_static_lib_optimized,
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 55705de9b2c..019609e6a5b 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -2625,18 +2625,18 @@ checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155"
 
 [[package]]
 name = "xshell"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
+checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
+checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547"
 
 [[package]]
 name = "xtask"
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index df7a5112f12..4d3e85ab1b2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -1,7 +1,7 @@
 use either::Either;
 use ide_db::FxHashMap;
 use itertools::Itertools;
-use syntax::{ast, ted, AstNode, SmolStr, ToSmolStr};
+use syntax::{ast, syntax_editor::SyntaxEditor, AstNode, SmolStr, SyntaxElement, ToSmolStr};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
@@ -24,6 +24,11 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     let record =
         path.syntax().parent().and_then(<Either<ast::RecordExpr, ast::RecordPat>>::cast)?;
 
+    let parent_node = match ctx.covering_element() {
+        SyntaxElement::Node(n) => n,
+        SyntaxElement::Token(t) => t.parent()?,
+    };
+
     let ranks = compute_fields_ranks(&path, ctx)?;
     let get_rank_of_field = |of: Option<SmolStr>| {
         *ranks.get(of.unwrap_or_default().trim_start_matches("r#")).unwrap_or(&usize::MAX)
@@ -65,23 +70,31 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         AssistId("reorder_fields", AssistKind::RefactorRewrite),
         "Reorder record fields",
         target,
-        |builder| match fields {
-            Either::Left((sorted, field_list)) => {
-                replace(builder.make_mut(field_list).fields(), sorted)
-            }
-            Either::Right((sorted, field_list)) => {
-                replace(builder.make_mut(field_list).fields(), sorted)
+        |builder| {
+            let mut editor = builder.make_editor(&parent_node);
+
+            match fields {
+                Either::Left((sorted, field_list)) => {
+                    replace(&mut editor, field_list.fields(), sorted)
+                }
+                Either::Right((sorted, field_list)) => {
+                    replace(&mut editor, field_list.fields(), sorted)
+                }
             }
+
+            builder.add_file_edits(ctx.file_id(), editor);
         },
     )
 }
 
 fn replace<T: AstNode + PartialEq>(
+    editor: &mut SyntaxEditor,
     fields: impl Iterator<Item = T>,
     sorted_fields: impl IntoIterator<Item = T>,
 ) {
     fields.zip(sorted_fields).for_each(|(field, sorted_field)| {
-        ted::replace(field.syntax(), sorted_field.syntax().clone_for_update())
+        // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
+        editor.replace(field.syntax(), sorted_field.syntax().clone_for_update())
     });
 }
 
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 3c0eb1b42a6..c97596d5097 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -183,7 +183,7 @@ impl<'a> Converter<'a> {
                 rustc_lexer::TokenKind::Ident => {
                     SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT)
                 }
-                rustc_lexer::TokenKind::InvalidPrefix | rustc_lexer::TokenKind::InvalidIdent => {
+                rustc_lexer::TokenKind::InvalidIdent => {
                     err = "Ident contains invalid characters";
                     IDENT
                 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index a5c9d2823e0..4975467ece9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -511,12 +511,16 @@ pub(crate) fn handle_document_diagnostics(
         .into_iter()
         .filter_map(|d| {
             let file = d.range.file_id;
-            let diagnostic = convert_diagnostic(&line_index, d);
             if file == file_id {
+                let diagnostic = convert_diagnostic(&line_index, d);
                 return Some(diagnostic);
             }
             if supports_related {
-                related_documents.entry(file).or_insert_with(Vec::new).push(diagnostic);
+                let (diagnostics, line_index) = related_documents
+                    .entry(file)
+                    .or_insert_with(|| (Vec::new(), snap.file_line_index(file).ok()));
+                let diagnostic = convert_diagnostic(line_index.as_mut()?, d);
+                diagnostics.push(diagnostic);
             }
             None
         });
@@ -529,7 +533,7 @@ pub(crate) fn handle_document_diagnostics(
             related_documents: related_documents.is_empty().not().then(|| {
                 related_documents
                     .into_iter()
-                    .map(|(id, items)| {
+                    .map(|(id, (items, _))| {
                         (
                             to_proto::url(&snap, id),
                             lsp_types::DocumentDiagnosticReportKind::Full(
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 327a547b295..68c481bda6e 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -3449,21 +3449,14 @@ impl Rewrite for ast::ForeignItem {
                     ref generics,
                     ref body,
                 } = **fn_kind;
-                if let Some(ref body) = body {
+                if body.is_some() {
                     let mut visitor = FmtVisitor::from_context(context);
                     visitor.block_indent = shape.indent;
                     visitor.last_pos = self.span.lo();
                     let inner_attrs = inner_attributes(&self.attrs);
                     let fn_ctxt = visit::FnCtxt::Foreign;
                     visitor.visit_fn(
-                        visit::FnKind::Fn(
-                            fn_ctxt,
-                            self.ident,
-                            sig,
-                            &self.vis,
-                            generics,
-                            Some(body),
-                        ),
+                        visit::FnKind::Fn(fn_ctxt, &self.ident, sig, &self.vis, generics, body),
                         &sig.decl,
                         self.span,
                         defaultness,
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 8102fe7ad8f..9b116b620b7 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -390,7 +390,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                 block = b;
                 self.rewrite_fn_before_block(
                     indent,
-                    ident,
+                    *ident,
                     &FnSig::from_fn_kind(&fk, fd, defaultness),
                     mk_sp(s.lo(), b.span.lo()),
                 )
@@ -540,21 +540,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                         ref generics,
                         ref body,
                     } = **fn_kind;
-                    if let Some(ref body) = body {
+                    if body.is_some() {
                         let inner_attrs = inner_attributes(&item.attrs);
                         let fn_ctxt = match sig.header.ext {
                             ast::Extern::None => visit::FnCtxt::Free,
                             _ => visit::FnCtxt::Foreign,
                         };
                         self.visit_fn(
-                            visit::FnKind::Fn(
-                                fn_ctxt,
-                                item.ident,
-                                sig,
-                                &item.vis,
-                                generics,
-                                Some(body),
-                            ),
+                            visit::FnKind::Fn(fn_ctxt, &item.ident, sig, &item.vis, generics, body),
                             &sig.decl,
                             item.span,
                             defaultness,
@@ -648,11 +641,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                     ref generics,
                     ref body,
                 } = **fn_kind;
-                if let Some(ref body) = body {
+                if body.is_some() {
                     let inner_attrs = inner_attributes(&ai.attrs);
                     let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
                     self.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
+                        visit::FnKind::Fn(fn_ctxt, &ai.ident, sig, &ai.vis, generics, body),
                         &sig.decl,
                         ai.span,
                         defaultness,
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index 751d678e581..a66ccd37070 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -10,26 +10,6 @@ use crate::walk::filter_not_rust;
 const LLVM_COMPONENTS_HEADER: &str = "needs-llvm-components:";
 const COMPILE_FLAGS_HEADER: &str = "compile-flags:";
 
-const KNOWN_LLVM_COMPONENTS: &[&str] = &[
-    "aarch64",
-    "arm",
-    "avr",
-    "bpf",
-    "csky",
-    "hexagon",
-    "loongarch",
-    "m68k",
-    "mips",
-    "msp430",
-    "nvptx",
-    "powerpc",
-    "riscv",
-    "sparc",
-    "systemz",
-    "webassembly",
-    "x86",
-];
-
 #[derive(Default, Debug)]
 struct RevisionInfo<'a> {
     target_arch: Option<&'a str>,
@@ -94,20 +74,6 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                     // gathered.
                 }
             }
-            if let Some(llvm_components) = llvm_components {
-                for component in llvm_components {
-                    // Ensure the given component even exists.
-                    // This is somewhat redundant with COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS,
-                    // but helps detect such problems earlier (PR CI rather than bors CI).
-                    if !KNOWN_LLVM_COMPONENTS.contains(component) {
-                        eprintln!(
-                            "{}: revision {} specifies unknown LLVM component `{}`",
-                            file, rev, component
-                        );
-                        *bad = true;
-                    }
-                }
-            }
         }
     });
 }
diff --git a/tests/assembly/s390x-vector-abi.rs b/tests/assembly/s390x-vector-abi.rs
new file mode 100644
index 00000000000..c1935582561
--- /dev/null
+++ b/tests/assembly/s390x-vector-abi.rs
@@ -0,0 +1,322 @@
+//@ revisions: z10 z10_vector z13 z13_no_vector
+// ignore-tidy-linelength
+//@ assembly-output: emit-asm
+//@ compile-flags: -O -Z merge-functions=disabled
+//@[z10] compile-flags: --target s390x-unknown-linux-gnu --cfg no_vector
+//@[z10] needs-llvm-components: systemz
+//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
+//@[z10_vector] needs-llvm-components: systemz
+//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13
+//@[z13] needs-llvm-components: systemz
+//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector --cfg no_vector
+//@[z13_no_vector] needs-llvm-components: systemz
+
+#![feature(no_core, lang_items, repr_simd, s390x_target_feature)]
+#![no_core]
+#![crate_type = "lib"]
+#![allow(non_camel_case_types)]
+
+// Cases where vector feature is disabled are rejected.
+// See tests/ui/simd-abi-checks-s390x.rs for test for them.
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "freeze"]
+pub trait Freeze {}
+
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+impl<T: ?Sized> Copy for PhantomData<T> {}
+
+#[repr(simd)]
+pub struct i8x8([i8; 8]);
+#[repr(simd)]
+pub struct i8x16([i8; 16]);
+#[repr(simd)]
+pub struct i8x32([i8; 32]);
+#[repr(C)]
+pub struct Wrapper<T>(T);
+#[repr(C, align(16))]
+pub struct WrapperAlign16<T>(T);
+#[repr(C)]
+pub struct WrapperWithZst<T>(T, PhantomData<()>);
+#[repr(transparent)]
+pub struct TransparentWrapper<T>(T);
+
+impl Copy for i8 {}
+impl Copy for i64 {}
+impl Copy for i8x8 {}
+impl Copy for i8x16 {}
+impl Copy for i8x32 {}
+impl<T: Copy> Copy for Wrapper<T> {}
+impl<T: Copy> Copy for WrapperAlign16<T> {}
+impl<T: Copy> Copy for WrapperWithZst<T> {}
+impl<T: Copy> Copy for TransparentWrapper<T> {}
+
+// CHECK-LABEL: vector_ret_small:
+// CHECK: vlrepg %v24, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+    *x
+}
+// CHECK-LABEL: vector_ret:
+// CHECK: vl %v24, 0(%r2), 3
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+    *x
+}
+// CHECK-LABEL: vector_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 0(%r3), 4
+// z13-NEXT: vl %v1, 16(%r3), 4
+// z13-NEXT: vst %v1, 16(%r2), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 {
+    *x
+}
+
+// CHECK-LABEL: vector_wrapper_ret_small:
+// CHECK: mvc 0(8,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_ret:
+// CHECK: mvc 0(16,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 16(%r3), 4
+// z13-NEXT: vst %v0, 16(%r2), 4
+// z13-NEXT: vl %v0, 0(%r3), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> {
+    *x
+}
+
+// CHECK-LABEL: vector_wrapper_padding_ret:
+// CHECK: mvc 0(16,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_padding_ret(x: &WrapperAlign16<i8x8>) -> WrapperAlign16<i8x8> {
+    *x
+}
+
+// CHECK-LABEL: vector_wrapper_with_zst_ret_small:
+// CHECK: mvc 0(8,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_ret_small(
+    x: &WrapperWithZst<i8x8>,
+) -> WrapperWithZst<i8x8> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_with_zst_ret:
+// CHECK: mvc 0(16,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_ret(
+    x: &WrapperWithZst<i8x16>,
+) -> WrapperWithZst<i8x16> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_with_zst_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 16(%r3), 4
+// z13-NEXT: vst %v0, 16(%r2), 4
+// z13-NEXT: vl %v0, 0(%r3), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_ret_large(
+    x: &WrapperWithZst<i8x32>,
+) -> WrapperWithZst<i8x32> {
+    *x
+}
+
+// CHECK-LABEL: vector_transparent_wrapper_ret_small:
+// CHECK: vlrepg %v24, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_ret_small(
+    x: &TransparentWrapper<i8x8>,
+) -> TransparentWrapper<i8x8> {
+    *x
+}
+// CHECK-LABEL: vector_transparent_wrapper_ret:
+// CHECK: vl %v24, 0(%r2), 3
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_ret(
+    x: &TransparentWrapper<i8x16>,
+) -> TransparentWrapper<i8x16> {
+    *x
+}
+// CHECK-LABEL: vector_transparent_wrapper_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 0(%r3), 4
+// z13-NEXT: vl %v1, 16(%r3), 4
+// z13-NEXT: vst %v1, 16(%r2), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_ret_large(
+    x: &TransparentWrapper<i8x32>,
+) -> TransparentWrapper<i8x32> {
+    *x
+}
+
+// CHECK-LABEL: vector_arg_small:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+    unsafe { *(&x as *const i8x8 as *const i64) }
+}
+// CHECK-LABEL: vector_arg:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_arg(x: i8x16) -> i64 {
+    unsafe { *(&x as *const i8x16 as *const i64) }
+}
+// CHECK-LABEL: vector_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 {
+    unsafe { *(&x as *const i8x32 as *const i64) }
+}
+
+// CHECK-LABEL: vector_wrapper_arg_small:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+    unsafe { *(&x as *const Wrapper<i8x8> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_arg:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+    unsafe { *(&x as *const Wrapper<i8x16> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 {
+    unsafe { *(&x as *const Wrapper<i8x32> as *const i64) }
+}
+
+// https://github.com/rust-lang/rust/pull/131586#discussion_r1837071121
+// CHECK-LABEL: vector_wrapper_padding_arg:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16<i8x8>) -> i64 {
+    unsafe { *(&x as *const WrapperAlign16<i8x8> as *const i64) }
+}
+
+// CHECK-LABEL: vector_wrapper_with_zst_arg_small:
+// CHECK: .cfi_startproc
+// CHECK-NOT: vlgvg
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst<i8x8>) -> i64 {
+    unsafe { *(&x as *const WrapperWithZst<i8x8> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_with_zst_arg:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst<i8x16>) -> i64 {
+    unsafe { *(&x as *const WrapperWithZst<i8x16> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_with_zst_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst<i8x32>) -> i64 {
+    unsafe { *(&x as *const WrapperWithZst<i8x32> as *const i64) }
+}
+
+// CHECK-LABEL: vector_transparent_wrapper_arg_small:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+    unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) }
+}
+// CHECK-LABEL: vector_transparent_wrapper_arg:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+    unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) }
+}
+// CHECK-LABEL: vector_transparent_wrapper_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 {
+    unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) }
+}
diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs
index 63f5c3d34f7..c612ddccdaa 100644
--- a/tests/codegen/checked_math.rs
+++ b/tests/codegen/checked_math.rs
@@ -90,7 +90,7 @@ pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
 #[no_mangle]
 pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 {
     // CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1
-    // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]]
+    // CHECK: br i1 %[[IS_MAX]], label %[[NONE_BB:.+]], label %[[SOME_BB:.+]],
     // CHECK: [[SOME_BB]]:
     // CHECK: %[[R:.+]] = add nuw i32 %x, 1
     // CHECK: ret i32 %[[R]]
diff --git a/tests/codegen/intrinsics/cold_path.rs b/tests/codegen/intrinsics/cold_path.rs
new file mode 100644
index 00000000000..24ee84e07bf
--- /dev/null
+++ b/tests/codegen/intrinsics/cold_path.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::cold_path;
+
+#[no_mangle]
+pub fn test_cold_path(x: bool) {
+    cold_path();
+}
+
+// CHECK-LABEL: @test_cold_path(
+// CHECK-NOT: cold_path
diff --git a/tests/codegen/intrinsics/likely.rs b/tests/codegen/intrinsics/likely.rs
index 9dc31d21045..e318390db20 100644
--- a/tests/codegen/intrinsics/likely.rs
+++ b/tests/codegen/intrinsics/likely.rs
@@ -1,22 +1,35 @@
-//@ compile-flags: -C no-prepopulate-passes -Copt-level=1
-
+//@ compile-flags: -O
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
 
-use std::intrinsics::{likely, unlikely};
+use std::intrinsics::likely;
 
+#[inline(never)]
 #[no_mangle]
-pub fn check_likely(x: i32, y: i32) -> Option<i32> {
-    unsafe {
-        // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true)
-        if likely(x == y) { None } else { Some(x + y) }
-    }
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
 }
 
 #[no_mangle]
-pub fn check_unlikely(x: i32, y: i32) -> Option<i32> {
-    unsafe {
-        // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false)
-        if unlikely(x == y) { None } else { Some(x + y) }
+pub fn test_likely(x: bool) {
+    if likely(x) {
+        path_a();
+    } else {
+        path_b();
     }
 }
+
+// CHECK-LABEL: @test_likely(
+// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
+// CHECK: bb3:
+// CHECK-NOT: cold_path
+// CHECK: path_b
+// CHECK: bb2:
+// CHECK: path_a
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen/intrinsics/likely_assert.rs b/tests/codegen/intrinsics/likely_assert.rs
new file mode 100644
index 00000000000..0ddbd6206ae
--- /dev/null
+++ b/tests/codegen/intrinsics/likely_assert.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test_assert(x: bool) {
+    assert!(x);
+}
+
+// check that assert! emits branch weights
+
+// CHECK-LABEL: @test_assert(
+// CHECK: br i1 %x, label %bb2, label %bb1, !prof ![[NUM:[0-9]+]]
+// CHECK: bb1:
+// CHECK: panic
+// CHECK: bb2:
+// CHECK: ret void
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen/intrinsics/unlikely.rs b/tests/codegen/intrinsics/unlikely.rs
new file mode 100644
index 00000000000..2d776031a52
--- /dev/null
+++ b/tests/codegen/intrinsics/unlikely.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::unlikely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test_unlikely(x: bool) {
+    if unlikely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+}
+
+// CHECK-LABEL: @test_unlikely(
+// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
+// CHECK: bb4:
+// CHECK: path_b
+// CHECK: bb2:
+// CHECK-NOT: cold_path
+// CHECK: path_a
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs
deleted file mode 100644
index 86677f416fe..00000000000
--- a/tests/crashes/113280.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: #113280
-//@ only-x86_64
-
-#![feature(dyn_star, pointer_like_trait)]
-#![allow(incomplete_features)]
-
-use std::fmt::Debug;
-use std::marker::PointerLike;
-
-fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
-    f32::from_bits(0x1) as f64
-}
-
-fn main() {
-    println!("{:?}", make_dyn_star(Box::new(1i32)));
-}
diff --git a/tests/crashes/123077-2.rs b/tests/crashes/123077-2.rs
deleted file mode 100644
index e086e330337..00000000000
--- a/tests/crashes/123077-2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ known-bug: #123077
-//@ only-x86_64
-use std::arch::x86_64::{__m128, _mm_blend_ps};
-
-pub fn sse41_blend_noinline( ) -> __m128 {
-    let f = { |x, y| unsafe {
-        _mm_blend_ps(x, y, { |x, y| unsafe })
-    }};
-    f(x, y)
-}
-
-pub fn main() {}
diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs
deleted file mode 100644
index 81149c2ef84..00000000000
--- a/tests/crashes/127676.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #127676
-//@ edition:2018
-
-#![feature(dyn_star,const_async_blocks)]
-
-static S: dyn* Send + Sync = async { 42 };
-
-pub fn main() {}
diff --git a/tests/crashes/129150.rs b/tests/crashes/129150.rs
deleted file mode 100644
index 9f8c2ba1739..00000000000
--- a/tests/crashes/129150.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ known-bug: rust-lang/rust#129150
-//@ only-x86_64
-use std::arch::x86_64::_mm_blend_ps;
-
-pub fn main() {
-     _mm_blend_ps(1, 2, &const {} );
-}
diff --git a/tests/crashes/130687.rs b/tests/crashes/130687.rs
deleted file mode 100644
index 361be0905df..00000000000
--- a/tests/crashes/130687.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: #130687
-//@ only-x86_64
-pub struct Data([u8; usize::MAX >> 16]);
-const _: &'static Data = &Data([0; usize::MAX >> 16]);
diff --git a/tests/crashes/131535.rs b/tests/crashes/131535.rs
deleted file mode 100644
index 47ccdf87f2d..00000000000
--- a/tests/crashes/131535.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: #131535
-#![feature(non_lifetime_binders)]
-trait v0<> {}
-fn kind  :(v0<'_, > impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {}
diff --git a/tests/crashes/131637.rs b/tests/crashes/131637.rs
deleted file mode 100644
index 7d328384a74..00000000000
--- a/tests/crashes/131637.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ known-bug: #121637
-#![feature(non_lifetime_binders)]
-trait Trait<Type> {
-    type Type;
-
-    fn method(&self) -> impl for<T> Trait<impl Trait<T>>;
-}
diff --git a/tests/crashes/132530.rs b/tests/crashes/132530.rs
deleted file mode 100644
index b43da62bfc1..00000000000
--- a/tests/crashes/132530.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #132530
-
-#![feature(non_lifetime_binders)]
-
-trait Trait<'a, A> {
-    type Assoc<'a> = i32;
-}
-
-fn a() -> impl for<T> Trait<Assoc = impl Trait<T>> {}
diff --git a/tests/crashes/132985.rs b/tests/crashes/132985.rs
new file mode 100644
index 00000000000..2735074f44d
--- /dev/null
+++ b/tests/crashes/132985.rs
@@ -0,0 +1,17 @@
+//@ known-bug: #132985
+//@ aux-build:aux132985.rs
+
+#![allow(incomplete_features)]
+#![feature(min_generic_const_args)]
+#![feature(adt_const_params)]
+
+extern crate aux132985;
+use aux132985::Foo;
+
+fn bar<const N: Foo>() {}
+
+fn baz() {
+    bar::<{ Foo }>();
+}
+
+fn main() {}
diff --git a/tests/crashes/auxiliary/aux132985.rs b/tests/crashes/auxiliary/aux132985.rs
new file mode 100644
index 00000000000..7ae5567bdc5
--- /dev/null
+++ b/tests/crashes/auxiliary/aux132985.rs
@@ -0,0 +1,6 @@
+#![feature(adt_const_params)]
+
+use std::marker::ConstParamTy;
+
+#[derive(Eq, PartialEq, ConstParamTy)]
+pub struct Foo;
diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs
index 9d232578979..9a0fd01d7e2 100644
--- a/tests/debuginfo/numeric-types.rs
+++ b/tests/debuginfo/numeric-types.rs
@@ -2,6 +2,14 @@
 
 //@ ignore-windows-gnu: #128981
 
+// Note: u128 visualization was not supported in 10.0.22621.3233 but was fixed in 10.0.26100.2161.
+
+// FIXME(#133107): this is temporarily marked as `only-64bit` because of course 32-bit msvc has
+// a different integer width and thus underlying integer type display. Only marked as such to
+// unblock the tree.
+//@ only-64bit
+//@ min-cdb-version: 10.0.26100.2161
+
 // Tests the visualizations for `NonZero<T>`, `Wrapping<T>` and
 // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`.
 
@@ -48,8 +56,8 @@
 // cdb-check:nz_u64           : 0x64 [Type: core::num::nonzero::NonZero<u64>]
 // cdb-check:    [<Raw View>]     [Type: core::num::nonzero::NonZero<u64>]
 
-// 128-bit integers don't seem to work in CDB
 // cdb-command: dx nz_u128
+// cdb-check:nz_u128          : 111 [Type: core::num::nonzero::NonZero<u128>]
 // cdb-check:    [<Raw View>]     [Type: core::num::nonzero::NonZero<u128>]
 
 // cdb-command: dx nz_usize
@@ -58,101 +66,99 @@
 
 // cdb-command: dx w_i8
 // cdb-check:w_i8             : 10 [Type: core::num::wrapping::Wrapping<i8>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<i8>]
+// cdb-check:    [+0x000] __0              : 10 [Type: char]
 
 // cdb-command: dx w_i16
 // cdb-check:w_i16            : 20 [Type: core::num::wrapping::Wrapping<i16>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<i16>]
+// cdb-check:    [+0x000] __0              : 20 [Type: short]
 
 // cdb-command: dx w_i32
 // cdb-check:w_i32            : 30 [Type: core::num::wrapping::Wrapping<i32>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<i32>]
+// cdb-check:    [+0x000] __0              : 30 [Type: int]
 
 // cdb-command: dx w_i64
 // cdb-check:w_i64            : 40 [Type: core::num::wrapping::Wrapping<i64>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<i64>]
+// cdb-check:    [+0x000] __0              : 40 [Type: __int64]
 
-// 128-bit integers don't seem to work in CDB
 // cdb-command: dx w_i128
-// cdb-check:w_i128           [Type: core::num::wrapping::Wrapping<i128>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<i128>]
+// cdb-check:w_i128           : 50 [Type: core::num::wrapping::Wrapping<i128>]
+// cdb-check:    [+0x000] __0              : 50 [Type: i128]
 
 // cdb-command: dx w_isize
 // cdb-check:w_isize          : 60 [Type: core::num::wrapping::Wrapping<isize>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<isize>]
+// cdb-check:    [+0x000] __0              : 60 [Type: __int64]
 
 // cdb-command: dx w_u8
 // cdb-check:w_u8             : 0x46 [Type: core::num::wrapping::Wrapping<u8>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<u8>]
+// cdb-check:    [+0x000] __0              : 0x46 [Type: unsigned char]
 
 // cdb-command: dx w_u16
 // cdb-check:w_u16            : 0x50 [Type: core::num::wrapping::Wrapping<u16>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<u16>]
+// cdb-check:    [+0x000] __0              : 0x50 [Type: unsigned short]
 
 // cdb-command: dx w_u32
 // cdb-check:w_u32            : 0x5a [Type: core::num::wrapping::Wrapping<u32>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<u32>]
+// cdb-check:    [+0x000] __0              : 0x5a [Type: unsigned int]
 
 // cdb-command: dx w_u64
 // cdb-check:w_u64            : 0x64 [Type: core::num::wrapping::Wrapping<u64>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<u64>]
+// cdb-check:    [+0x000] __0              : 0x64 [Type: unsigned __int64]
 
-// 128-bit integers don't seem to work in CDB
 // cdb-command: dx w_u128
-// cdb-check:w_u128           [Type: core::num::wrapping::Wrapping<u128>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<u128>]
+// cdb-check:w_u128           : 110 [Type: core::num::wrapping::Wrapping<u128>]
+// cdb-check:    [+0x000] __0              : 110 [Type: u128]
 
 // cdb-command: dx w_usize
 // cdb-check:w_usize          : 0x78 [Type: core::num::wrapping::Wrapping<usize>]
-// cdb-check:    [<Raw View>]     [Type: core::num::wrapping::Wrapping<usize>]
+// cdb-check:    [+0x000] __0              : 0x78 [Type: unsigned __int64]
 
 // cdb-command: dx a_bool_t
 // cdb-check:a_bool_t         : true [Type: core::sync::atomic::AtomicBool]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicBool]
+// cdb-check:    [+0x000] v                : 0x1 [Type: core::cell::UnsafeCell<u8>]
 
 // cdb-command: dx a_bool_f
 // cdb-check:a_bool_f         : false [Type: core::sync::atomic::AtomicBool]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicBool]
+// cdb-check:    [+0x000] v                : 0x0 [Type: core::cell::UnsafeCell<u8>]
 
 // cdb-command: dx a_i8
 // cdb-check:a_i8             : 2 [Type: core::sync::atomic::AtomicI8]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicI8]
+// cdb-check:    [+0x000] v                : 2 [Type: core::cell::UnsafeCell<i8>]
 
 // cdb-command: dx a_i16
 // cdb-check:a_i16            : 4 [Type: core::sync::atomic::AtomicI16]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicI16]
+// cdb-check:    [+0x000] v                : 4 [Type: core::cell::UnsafeCell<i16>]
 
 // cdb-command: dx a_i32
 // cdb-check:a_i32            : 8 [Type: core::sync::atomic::AtomicI32]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicI32]
+// cdb-check:    [+0x000] v                : 8 [Type: core::cell::UnsafeCell<i32>]
 
 // cdb-command: dx a_i64
 // cdb-check:a_i64            : 16 [Type: core::sync::atomic::AtomicI64]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicI64]
+// cdb-check:    [+0x000] v                : 16 [Type: core::cell::UnsafeCell<i64>]
 
 // cdb-command: dx a_isize
 // cdb-check:a_isize          : 32 [Type: core::sync::atomic::AtomicIsize]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicIsize]
+// cdb-check:    [+0x000] v                : 32 [Type: core::cell::UnsafeCell<isize>]
 
 // cdb-command: dx a_u8
 // cdb-check:a_u8             : 0x40 [Type: core::sync::atomic::AtomicU8]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicU8]
+// cdb-check:    [+0x000] v                : 0x40 [Type: core::cell::UnsafeCell<u8>]
 
 // cdb-command: dx a_u16
 // cdb-check:a_u16            : 0x80 [Type: core::sync::atomic::AtomicU16]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicU16]
+// cdb-check:    [+0x000] v                : 0x80 [Type: core::cell::UnsafeCell<u16>]
 
 // cdb-command: dx a_u32
 // cdb-check:a_u32            : 0x100 [Type: core::sync::atomic::AtomicU32]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicU32]
+// cdb-check:    [+0x000] v                : 0x100 [Type: core::cell::UnsafeCell<u32>]
 
 // cdb-command: dx a_u64
 // cdb-check:a_u64            : 0x200 [Type: core::sync::atomic::AtomicU64]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicU64]
+// cdb-check:    [+0x000] v                : 0x200 [Type: core::cell::UnsafeCell<u64>]
 
 // cdb-command: dx a_usize
 // cdb-check:a_usize          : 0x400 [Type: core::sync::atomic::AtomicUsize]
-// cdb-check:    [<Raw View>]     [Type: core::sync::atomic::AtomicUsize]
+// cdb-check:    [+0x000] v                : 0x400 [Type: core::cell::UnsafeCell<usize>]
 
 
 // === GDB TESTS ===================================================================================
diff --git a/tests/debuginfo/range-types.rs b/tests/debuginfo/range-types.rs
index 8c18fd9addd..068a55a5767 100644
--- a/tests/debuginfo/range-types.rs
+++ b/tests/debuginfo/range-types.rs
@@ -1,7 +1,10 @@
 // Testing the display of range types in cdb.
 
-// cdb-only
-//@ min-cdb-version: 10.0.18317.1001
+//@ only-cdb
+
+// FIXME(jieyouxu): triple check in CI if the directive actually works
+//@ min-cdb-version: 10.0.26100.2161
+
 //@ compile-flags:-g
 
 // === CDB TESTS ==================================================================================
@@ -10,23 +13,26 @@
 
 // cdb-command: dx r1,d
 // cdb-check:r1,d             : (3..5) [Type: core::ops::range::Range<i32>]
-// cdb-check:    [<Raw View>]     [Type: core::ops::range::Range<i32>]
+// cdb-check:    [+0x000] start            : 3 [Type: int]
+// cdb-check:    [+0x004] end              : 5 [Type: int]
 
 // cdb-command: dx r2,d
 // cdb-check:r2,d             : (2..) [Type: core::ops::range::RangeFrom<i32>]
-// cdb-check:    [<Raw View>]     [Type: core::ops::range::RangeFrom<i32>]
+// cdb-check:    [+0x000] start            : 2 [Type: int]
 
 // cdb-command: dx r3,d
 // cdb-check:r3,d             : (1..=4) [Type: core::ops::range::RangeInclusive<i32>]
-// cdb-check:    [<Raw View>]     [Type: core::ops::range::RangeInclusive<i32>]
+// cdb-check:    [+0x000] start            : 1 [Type: int]
+// cdb-check:    [+0x004] end              : 4 [Type: int]
+// cdb-check:    [+0x008] exhausted        : false [Type: bool]
 
 // cdb-command: dx r4,d
 // cdb-check:r4,d             : (..10) [Type: core::ops::range::RangeTo<i32>]
-// cdb-check:    [<Raw View>]     [Type: core::ops::range::RangeTo<i32>]
+// cdb-check:    [+0x000] end              : 10 [Type: int]
 
 // cdb-command: dx r5,d
 // cdb-check:r5,d             : (..=3) [Type: core::ops::range::RangeToInclusive<i32>]
-// cdb-check:    [<Raw View>]     [Type: core::ops::range::RangeToInclusive<i32>]
+// cdb-check:    [+0x000] end              : 3 [Type: int]
 
 // cdb-command: dx r6,d
 // cdb-check:r6,d             [Type: core::ops::range::RangeFull]
diff --git a/tests/debuginfo/unit-type.rs b/tests/debuginfo/unit-type.rs
index 42c0ff11f71..0ffa2fe490a 100644
--- a/tests/debuginfo/unit-type.rs
+++ b/tests/debuginfo/unit-type.rs
@@ -1,5 +1,8 @@
 //@ compile-flags:-g
 
+// FIXME(jieyouxu): triple check if this works in CI
+//@ min-cdb-version: 10.0.26100.2161
+
 // === GDB TESTS ===================================================================================
 
 // gdb-command: run
@@ -26,18 +29,18 @@
 // cdb-check: Breakpoint 0 hit
 
 // cdb-command: dx _ref
-// cdb-check: _ref             : 0x[...] : () [Type: tuple$<> *]
+// cdb-check: _ref             : 0x[...] [Type: tuple$<> *]
 
 // cdb-command: dx _ptr
-// cdb-check: _ptr             : 0x[...] : () [Type: tuple$<> *]
+// cdb-check: _ptr             : 0x[...] [Type: tuple$<> *]
 
 // cdb-command: dx _local
-// cdb-check: _local           : () [Type: tuple$<>]
+// cdb-check: _local           [Type: tuple$<>]
 
 // cdb-command: dx _field,d
 // cdb-check: _field,d         [Type: unit_type::_TypeContainingUnitField]
 // cdb-check:     [+0x[...]] _a               : 123 [Type: unsigned int]
-// cdb-check:     [+0x[...]] _unit            : () [Type: tuple$<>]
+// cdb-check:     [+0x[...]] _unit            [Type: tuple$<>]
 // cdb-check:     [+0x[...]] _b               : 456 [Type: unsigned __int64]
 
 // Check that we can cast "void pointers" to their actual type in the debugger
diff --git a/tests/incremental/hygiene/load_cached_hygiene.rs b/tests/incremental/hygiene/load_cached_hygiene.rs
index 4ad9c7d49fd..101d280cd49 100644
--- a/tests/incremental/hygiene/load_cached_hygiene.rs
+++ b/tests/incremental/hygiene/load_cached_hygiene.rs
@@ -7,7 +7,7 @@
 //    This causes hygiene information to be saved to the incr cache.
 // 2. One function is the foreign crate is modified. This causes the
 //    optimized mir for an unmodified function to be loaded from the
-//@    incremental cache and written out to the crate metadata.
+//    incremental cache and written out to the crate metadata.
 // 3. In the process of loading and writing out this function's MIR,
 //    we load hygiene information from the incremental cache and
 //    write it to our metadata.
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
index 935e67fc3c0..cff5b4c7243 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir
@@ -13,7 +13,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
                 scope 6 (inlined core::num::<impl u16>::checked_add) {
                     let mut _5: (u16, bool);
                     let mut _6: bool;
-                    let mut _7: bool;
+                    scope 7 (inlined unlikely) {
+                        let _7: ();
+                    }
                 }
             }
             scope 5 (inlined convert::num::ptr_try_from_impls::<impl TryFrom<usize> for u16>::try_from) {
@@ -21,11 +23,11 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
                 let mut _4: u16;
             }
         }
-        scope 7 (inlined Option::<u16>::is_none) {
-            scope 8 (inlined Option::<u16>::is_some) {
+        scope 8 (inlined Option::<u16>::is_none) {
+            scope 9 (inlined Option::<u16>::is_some) {
             }
         }
-        scope 9 (inlined core::num::<impl u16>::wrapping_add) {
+        scope 10 (inlined core::num::<impl u16>::wrapping_add) {
         }
     }
 
@@ -39,29 +41,26 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
     bb1: {
         _4 = copy _2 as u16 (IntToInt);
         StorageDead(_3);
-        StorageLive(_7);
         StorageLive(_6);
         StorageLive(_5);
         _5 = AddWithOverflow(copy _1, copy _4);
         _6 = copy (_5.1: bool);
-        _7 = unlikely(move _6) -> [return: bb2, unwind unreachable];
+        switchInt(copy _6) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        switchInt(move _7) -> [0: bb3, otherwise: bb4];
-    }
-
-    bb3: {
         StorageDead(_5);
         StorageDead(_6);
-        StorageDead(_7);
         goto -> bb7;
     }
 
+    bb3: {
+        _7 = cold_path() -> [return: bb4, unwind unreachable];
+    }
+
     bb4: {
         StorageDead(_5);
         StorageDead(_6);
-        StorageDead(_7);
         goto -> bb6;
     }
 
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
index bf1ffd1ef32..6e0242a220d 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir
@@ -13,7 +13,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
                 scope 6 (inlined core::num::<impl u16>::checked_add) {
                     let mut _5: (u16, bool);
                     let mut _6: bool;
-                    let mut _7: bool;
+                    scope 7 (inlined unlikely) {
+                        let _7: ();
+                    }
                 }
             }
             scope 5 (inlined convert::num::ptr_try_from_impls::<impl TryFrom<usize> for u16>::try_from) {
@@ -21,11 +23,11 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
                 let mut _4: u16;
             }
         }
-        scope 7 (inlined Option::<u16>::is_none) {
-            scope 8 (inlined Option::<u16>::is_some) {
+        scope 8 (inlined Option::<u16>::is_none) {
+            scope 9 (inlined Option::<u16>::is_some) {
             }
         }
-        scope 9 (inlined core::num::<impl u16>::wrapping_add) {
+        scope 10 (inlined core::num::<impl u16>::wrapping_add) {
         }
     }
 
@@ -39,29 +41,26 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
     bb1: {
         _4 = copy _2 as u16 (IntToInt);
         StorageDead(_3);
-        StorageLive(_7);
         StorageLive(_6);
         StorageLive(_5);
         _5 = AddWithOverflow(copy _1, copy _4);
         _6 = copy (_5.1: bool);
-        _7 = unlikely(move _6) -> [return: bb2, unwind unreachable];
+        switchInt(copy _6) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        switchInt(move _7) -> [0: bb3, otherwise: bb4];
-    }
-
-    bb3: {
         StorageDead(_5);
         StorageDead(_6);
-        StorageDead(_7);
         goto -> bb7;
     }
 
+    bb3: {
+        _7 = cold_path() -> [return: bb4, unwind unreachable];
+    }
+
     bb4: {
         StorageDead(_5);
         StorageDead(_6);
-        StorageDead(_7);
         goto -> bb6;
     }
 
diff --git a/tests/run-make/mte-ffi/rmake.rs b/tests/run-make/mte-ffi/rmake.rs
index f4fafb796e3..50f5f14191b 100644
--- a/tests/run-make/mte-ffi/rmake.rs
+++ b/tests/run-make/mte-ffi/rmake.rs
@@ -1,14 +1,12 @@
-// Tests that MTE tags and values stored in the top byte of a pointer (TBI) are
-// preserved across 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.
+//! Tests that MTE tags and values stored in the top byte of a pointer (TBI) are preserved across
+//! 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.
 
-// This test is only valid for AArch64.
-// The linker must be explicitly specified when cross-compiling, so it is limited to
-// `aarch64-unknown-linux-gnu`.
 //@ 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`.
 
-use run_make_support::{cc, dynamic_lib_name, extra_c_flags, run, rustc, target};
+use run_make_support::{dynamic_lib_name, extra_c_flags, gcc, run, rustc, target};
 
 fn main() {
     run_test("int");
@@ -29,7 +27,8 @@ fn run_test(variant: &str) {
         .target(target())
         .linker("aarch64-linux-gnu-gcc")
         .run();
-    cc().input(format!("bar_{variant}.c"))
+    gcc()
+        .input(format!("bar_{variant}.c"))
         .input(dynamic_lib_name("foo"))
         .out_exe("test")
         .args(&flags)
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
index cf6e3d86377..0a2186b0953 100644
--- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
@@ -10,14 +10,16 @@
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
-use run_make_support::{clang, env_var, llvm_ar, run, rustc, static_lib_name};
+use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, run, rustc, static_lib_name};
+
+static PAUTH_A_KEY_PATTERN: &'static str = "paciasp";
+static PAUTH_B_KEY_PATTERN: &'static str = "pacibsp";
 
 fn main() {
     clang()
         .arg("-v")
         .lto("thin")
-        .arg("-mbranch-protection=bti+pac-ret+leaf")
-        .arg("-O2")
+        .arg("-mbranch-protection=bti+pac-ret+b-key+leaf")
         .arg("-c")
         .out_exe("test.o")
         .input("test.c")
@@ -32,5 +34,15 @@ fn main() {
         .input("test.rs")
         .output("test.bin")
         .run();
+
+    // Check that both a-key and b-key pac-ret survived LTO
+    llvm_objdump()
+        .disassemble()
+        .input("test.bin")
+        .run()
+        .assert_stdout_contains_regex(PAUTH_A_KEY_PATTERN)
+        .assert_stdout_contains_regex(PAUTH_B_KEY_PATTERN);
+
+    // Check that the binary actually runs
     run("test.bin");
 }
diff --git a/tests/run-make/unstable-feature-usage-metrics/lib.rs b/tests/run-make/unstable-feature-usage-metrics/lib.rs
new file mode 100644
index 00000000000..2202d722c49
--- /dev/null
+++ b/tests/run-make/unstable-feature-usage-metrics/lib.rs
@@ -0,0 +1,9 @@
+#![feature(ascii_char)] // random lib feature
+#![feature(box_patterns)] // random lang feature
+
+// picked arbitrary unstable features, just need a random lib and lang feature, ideally ones that
+// won't be stabilized any time soon so we don't have to update this test
+
+fn main() {
+    println!("foobar");
+}
diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
new file mode 100644
index 00000000000..1397548a6fc
--- /dev/null
+++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
@@ -0,0 +1,87 @@
+//! This test checks if unstable feature usage metric dump files `unstable-feature-usage*.json` work
+//! as expected.
+//!
+//! - Basic sanity checks on a default ICE dump.
+//!
+//! See <https://github.com/rust-lang/rust/issues/129485>.
+//!
+//! # Test history
+//!
+//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
+//! those will be present in this test as well on the same platform
+
+//@ ignore-windows
+//FIXME(#128911): still flakey on i686-mingw.
+
+use std::path::{Path, PathBuf};
+
+use run_make_support::rfs::create_dir_all;
+use run_make_support::{
+    cwd, filename_contains, has_extension, rfs, run_in_tmpdir, rustc, serde_json,
+    shallow_find_files,
+};
+
+fn find_feature_usage_metrics<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
+    shallow_find_files(dir, |path| {
+        if filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") {
+            true
+        } else {
+            dbg!(path);
+            false
+        }
+    })
+}
+
+fn main() {
+    test_metrics_dump();
+    test_metrics_errors();
+}
+
+#[track_caller]
+fn test_metrics_dump() {
+    run_in_tmpdir(|| {
+        let metrics_dir = cwd().join("metrics");
+        create_dir_all(&metrics_dir);
+        rustc()
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "short")
+            .arg(format!("-Zmetrics-dir={}", metrics_dir.display()))
+            .run();
+        let mut metrics = find_feature_usage_metrics(&metrics_dir);
+        let json_path =
+            metrics.pop().expect("there should be one metrics file in the output directory");
+
+        // After the `pop` above, there should be no files left.
+        assert!(
+            metrics.is_empty(),
+            "there should be no more than one metrics file in the output directory"
+        );
+
+        let message = rfs::read_to_string(json_path);
+        let parsed: serde_json::Value =
+            serde_json::from_str(&message).expect("metrics should be dumped as json");
+        let expected = serde_json::json!(
+            {
+                "lib_features":[{"symbol":"ascii_char"}],
+                "lang_features":[{"symbol":"box_patterns","since":null}]
+            }
+        );
+
+        assert_eq!(expected, parsed);
+    });
+}
+
+#[track_caller]
+fn test_metrics_errors() {
+    run_in_tmpdir(|| {
+        rustc()
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "short")
+            .arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
+            .run_fail()
+            .assert_stderr_contains(
+                "error: cannot dump feature usage metrics: No such file or directory",
+            )
+            .assert_stdout_not_contains("internal compiler error");
+    });
+}
diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js
index 068298e7236..8bffef61c8f 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -144,14 +144,6 @@ const PARSED = [
         error: "Unexpected `:: ::`",
     },
     {
-        query: "a::b::",
-        elems: [],
-        foundElems: 0,
-        userQuery: "a::b::",
-        returned: [],
-        error: "Paths cannot end with `::`",
-    },
-    {
         query: ":a",
         elems: [],
         foundElems: 0,
diff --git a/tests/rustdoc-js-std/path-end-empty.js b/tests/rustdoc-js-std/path-end-empty.js
new file mode 100644
index 00000000000..6e853c61b4d
--- /dev/null
+++ b/tests/rustdoc-js-std/path-end-empty.js
@@ -0,0 +1,6 @@
+const EXPECTED = {
+    'query': 'Option::',
+    'others': [
+        { 'path': 'std::option::Option', 'name': 'get_or_insert_default' },
+    ],
+}
diff --git a/tests/rustdoc-js/trailing.js b/tests/rustdoc-js/trailing.js
new file mode 100644
index 00000000000..df5dd22ca4e
--- /dev/null
+++ b/tests/rustdoc-js/trailing.js
@@ -0,0 +1,7 @@
+// exact-check
+const EXPECTED = {
+    'query': 'inner::',
+    'others': [
+        { 'path': 'trailing::inner', 'name': 'function' },
+    ],
+}
diff --git a/tests/rustdoc-js/trailing.rs b/tests/rustdoc-js/trailing.rs
new file mode 100644
index 00000000000..5c7c9362ffb
--- /dev/null
+++ b/tests/rustdoc-js/trailing.rs
@@ -0,0 +1,3 @@
+pub mod inner {
+    pub fn function() {}
+}
diff --git a/tests/rustdoc/link-on-path-with-generics.rs b/tests/rustdoc/link-on-path-with-generics.rs
new file mode 100644
index 00000000000..22ba36c9f15
--- /dev/null
+++ b/tests/rustdoc/link-on-path-with-generics.rs
@@ -0,0 +1,14 @@
+// This test ensures that paths with generics still get their link to their definition
+// correctly generated.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+#![crate_name = "foo"]
+
+//@ has 'src/foo/link-on-path-with-generics.rs.html'
+
+pub struct Soyo<T>(T);
+pub struct Saya;
+
+//@ has - '//pre[@class="rust"]//a[@href="#9"]' 'Soyo'
+//@ has - '//pre[@class="rust"]//a[@href="#10"]' 'Saya'
+pub fn bar<T>(s: Soyo<T>, x: Saya) {}
diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
index d7f37f36681..3534228f73e 100644
--- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
+++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
@@ -64,7 +64,7 @@ fn check_instance(instance: &Instance) {
     if instance.has_body() {
         let Some(body) = instance.body() else { unreachable!("Expected a body") };
         assert!(!body.blocks.is_empty());
-        assert_eq!(&name, "likely");
+        assert_eq!(&name, "select_unpredictable");
     } else {
         assert!(instance.body().is_none());
         assert_matches!(name.as_str(), "size_of_val" | "vtable_size");
@@ -78,7 +78,7 @@ fn check_def(fn_def: FnDef) {
 
     let name = intrinsic.fn_name();
     match name.as_str() {
-        "likely" => {
+        "select_unpredictable" => {
             assert!(!intrinsic.must_be_overridden());
             assert!(fn_def.has_body());
         }
@@ -132,7 +132,7 @@ fn generate_input(path: &str) -> std::io::Result<()> {
         pub fn use_intrinsics(init: bool) -> bool {{
             let vtable_sz = unsafe {{ vtable_size(0 as *const ()) }};
             let sz = unsafe {{ size_of_val("hi") }};
-            likely(init && sz == 2)
+            select_unpredictable(init && sz == 2, false, true)
         }}
         "#
     )?;
diff --git a/tests/ui/asm/x86_64/goto-block-safe.rs b/tests/ui/asm/x86_64/goto-block-safe.rs
new file mode 100644
index 00000000000..ee833a48a4b
--- /dev/null
+++ b/tests/ui/asm/x86_64/goto-block-safe.rs
@@ -0,0 +1,23 @@
+//@ only-x86_64
+//@ needs-asm-support
+
+#![deny(unreachable_code)]
+#![feature(asm_goto)]
+
+use std::arch::asm;
+
+fn goto_fallthough() {
+    unsafe {
+        asm!(
+            "/* {} */",
+            label {
+                core::hint::unreachable_unchecked();
+                //~^ ERROR [E0133]
+            }
+        )
+    }
+}
+
+fn main() {
+    goto_fallthough();
+}
diff --git a/tests/ui/asm/x86_64/goto-block-safe.stderr b/tests/ui/asm/x86_64/goto-block-safe.stderr
new file mode 100644
index 00000000000..49818db7484
--- /dev/null
+++ b/tests/ui/asm/x86_64/goto-block-safe.stderr
@@ -0,0 +1,14 @@
+error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block
+  --> $DIR/goto-block-safe.rs:14:17
+   |
+LL |     unsafe {
+   |     ------ items do not inherit unsafety from separate enclosing items
+...
+LL |                 core::hint::unreachable_unchecked();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/auxiliary/pub-and-stability.rs b/tests/ui/auxiliary/pub-and-stability.rs
index ee05a07dbb2..d2d07f99398 100644
--- a/tests/ui/auxiliary/pub-and-stability.rs
+++ b/tests/ui/auxiliary/pub-and-stability.rs
@@ -5,8 +5,8 @@
 // The basic stability pattern in this file has four cases:
 // 1. no stability attribute at all
 // 2. a stable attribute (feature "unit_test")
-// 3. an unstable attribute that unit test declares (feature "unstable_declared")
-// 4. an unstable attribute that unit test fails to declare (feature "unstable_undeclared")
+// 3. an unstable attribute that unit test enables (feature "unstable_declared")
+// 4. an unstable attribute that unit test fails to enable (feature "unstable_undeclared")
 //
 // This file also covers four kinds of visibility: private,
 // pub(module), pub(crate), and pub.
diff --git a/tests/ui/bootstrap/rustc_bootstap.force_stable.stderr b/tests/ui/bootstrap/rustc_bootstap.force_stable.stderr
new file mode 100644
index 00000000000..f378f3c70dd
--- /dev/null
+++ b/tests/ui/bootstrap/rustc_bootstap.force_stable.stderr
@@ -0,0 +1,10 @@
+error: the option `Z` is only accepted on the nightly compiler
+
+help: consider switching to a nightly toolchain: `rustup default nightly`
+
+note: selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>
+
+note: for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>
+
+error: 1 nightly option were parsed
+
diff --git a/tests/ui/bootstrap/rustc_bootstap.rs b/tests/ui/bootstrap/rustc_bootstap.rs
new file mode 100644
index 00000000000..3d792ef4be4
--- /dev/null
+++ b/tests/ui/bootstrap/rustc_bootstap.rs
@@ -0,0 +1,47 @@
+//! Check `RUSTC_BOOTSTRAP`'s behavior in relation to feature stability and what rustc considers
+//! itself to be (stable vs non-stable ).
+//!
+//! `RUSTC_BOOTSTRAP` accepts:
+//!
+//! - `1`: cheat, allow usage of unstable features even if rustc thinks it is a stable compiler.
+//! - `x,y,z`: comma-delimited list of crates.
+//! - `-1`: force rustc to think it is a stable compiler.
+
+// ignore-tidy-linelength
+
+//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable invalid_zero invalid_junk
+//@ only-nightly
+
+//@[default_nightly] unset-rustc-env:RUSTC_BOOTSTRAP
+//@[default_nightly] check-pass
+
+// For a nightly compiler, this is same as `default_nightly` as if `RUSTC_BOOTSTRAP` was unset.
+//@[invalid_zero] rustc-env:RUSTC_BOOTSTRAP=0
+//@[invalid_zero] check-pass
+
+// Invalid values are silently discarded, same as `default_nightly`, i.e. as if `RUSTC_BOOTSTRAP`
+// was unset.
+//@[invalid_junk] rustc-env:RUSTC_BOOTSTRAP=*
+//@[invalid_junk] check-pass
+
+//@[cheat] rustc-env:RUSTC_BOOTSTRAP=1
+//@[cheat] check-pass
+
+//@[cheat_single_crate] rustc-env:RUSTC_BOOTSTRAP=x
+//@[cheat_single_crate] check-pass
+
+//@[cheat_multi_crate] rustc-env:RUSTC_BOOTSTRAP=x,y,z
+//@[cheat_multi_crate] check-pass
+
+// Note: compiletest passes some `-Z` flags to the compiler for ui testing purposes, so here we
+// instead abuse the fact that `-Z unstable-options` is also part of rustc's stability story and is
+// also affected by `RUSTC_BOOTSTRAP`.
+//@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1
+//@[force_stable] compile-flags: -Z unstable-options
+//@[force_stable] regex-error-pattern: error: the option `Z` is only accepted on the nightly compiler
+
+#![crate_type = "lib"]
+
+// Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is
+// used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic.
+#![feature(rustc_attrs)]
diff --git a/tests/ui/check-cfg/auxiliary/cfg_macro.rs b/tests/ui/check-cfg/auxiliary/cfg_macro.rs
new file mode 100644
index 00000000000..d68accd9202
--- /dev/null
+++ b/tests/ui/check-cfg/auxiliary/cfg_macro.rs
@@ -0,0 +1,11 @@
+// Inspired by https://github.com/rust-lang/cargo/issues/14775
+
+pub fn my_lib_func() {}
+
+#[macro_export]
+macro_rules! my_lib_macro {
+    () => {
+        #[cfg(my_lib_cfg)]
+        $crate::my_lib_func()
+    };
+}
diff --git a/tests/ui/check-cfg/report-in-external-macros.rs b/tests/ui/check-cfg/report-in-external-macros.rs
new file mode 100644
index 00000000000..56550b04af3
--- /dev/null
+++ b/tests/ui/check-cfg/report-in-external-macros.rs
@@ -0,0 +1,12 @@
+// This test checks that we emit the `unexpected_cfgs` lint even in code
+// coming from an external macro.
+
+//@ check-pass
+//@ no-auto-check-cfg
+//@ aux-crate: cfg_macro=cfg_macro.rs
+//@ compile-flags: --check-cfg=cfg()
+
+fn main() {
+    cfg_macro::my_lib_macro!();
+    //~^ WARNING unexpected `cfg` condition name
+}
diff --git a/tests/ui/check-cfg/report-in-external-macros.stderr b/tests/ui/check-cfg/report-in-external-macros.stderr
new file mode 100644
index 00000000000..11300a4e402
--- /dev/null
+++ b/tests/ui/check-cfg/report-in-external-macros.stderr
@@ -0,0 +1,14 @@
+warning: unexpected `cfg` condition name: `my_lib_cfg`
+  --> $DIR/report-in-external-macros.rs:10:5
+   |
+LL |     cfg_macro::my_lib_macro!();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `fmt_debug`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(my_lib_cfg)`
+   = 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
+   = note: this warning originates in the macro `cfg_macro::my_lib_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
index ca8c2a16d32..5f980c46a1f 100644
--- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
+++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
@@ -97,16 +97,19 @@ LL |         if let Refutable::A = v3 { todo!() };
 error[E0005]: refutable pattern in local binding
   --> $DIR/bad-pattern.rs:19:13
    |
+LL |     const PAT: u32 = 0;
+   |     -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
+...
 LL |         let PAT = v1;
-   |             ^^^
-   |             |
-   |             pattern `1_u32..=u32::MAX` not covered
-   |             missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
-   |             help: introduce a variable instead: `PAT_var`
+   |             ^^^ pattern `1_u32..=u32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u32`
+help: introduce a variable instead
+   |
+LL |         let PAT_var = v1;
+   |             ~~~~~~~
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/closures/correct-args-on-call-suggestion.rs b/tests/ui/closures/correct-args-on-call-suggestion.rs
new file mode 100644
index 00000000000..fa7915a7c03
--- /dev/null
+++ b/tests/ui/closures/correct-args-on-call-suggestion.rs
@@ -0,0 +1,7 @@
+// Ensure we give the right args when we suggest calling a closure.
+
+fn main() {
+    let x = |a: i32, b: i32| a + b;
+    let y: i32 = x;
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/closures/correct-args-on-call-suggestion.stderr b/tests/ui/closures/correct-args-on-call-suggestion.stderr
new file mode 100644
index 00000000000..2613c7776b2
--- /dev/null
+++ b/tests/ui/closures/correct-args-on-call-suggestion.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/correct-args-on-call-suggestion.rs:5:18
+   |
+LL |     let x = |a: i32, b: i32| a + b;
+   |             ---------------- the found closure
+LL |     let y: i32 = x;
+   |            ---   ^ expected `i32`, found closure
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+           found closure `{closure@$DIR/correct-args-on-call-suggestion.rs:4:13: 4:29}`
+help: use parentheses to call this closure
+   |
+LL |     let y: i32 = x(/* i32 */, /* i32 */);
+   |                   ++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs
new file mode 100644
index 00000000000..fc4258fc0af
--- /dev/null
+++ b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.rs
@@ -0,0 +1,18 @@
+//@ check-fail
+fn main() {
+    let x = Box::new(Some(1));
+
+    let test: Option<i32> = x;
+    //~^ ERROR mismatched types
+    let x = Box::new(Some(1));
+    let test: Option<i32> = { x as Box<Option<i32>> };
+    //~^ ERROR mismatched types
+
+    let x = Box::new(Some(1));
+    let test: Option<i32> = if true { x as Box<Option<i32>> } else { None };
+    //~^ ERROR mismatched types
+
+    let x = std::rc::Rc::new(Some(1));
+    let test: Option<i32> = x as std::rc::Rc<Option<i32>>;
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr
new file mode 100644
index 00000000000..429b1b87357
--- /dev/null
+++ b/tests/ui/coercion/unboxing-needing-parenthases-issue-132924.stderr
@@ -0,0 +1,59 @@
+error[E0308]: mismatched types
+  --> $DIR/unboxing-needing-parenthases-issue-132924.rs:5:29
+   |
+LL |     let test: Option<i32> = x;
+   |               -----------   ^ expected `Option<i32>`, found `Box<Option<{integer}>>`
+   |               |
+   |               expected due to this
+   |
+   = note: expected enum `Option<i32>`
+            found struct `Box<Option<{integer}>>`
+help: consider unboxing the value
+   |
+LL |     let test: Option<i32> = *x;
+   |                             +
+
+error[E0308]: mismatched types
+  --> $DIR/unboxing-needing-parenthases-issue-132924.rs:8:31
+   |
+LL |     let test: Option<i32> = { x as Box<Option<i32>> };
+   |                               ^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Box<Option<i32>>`
+   |
+   = note: expected enum `Option<_>`
+            found struct `Box<Option<_>>`
+help: consider unboxing the value
+   |
+LL |     let test: Option<i32> = { *(x as Box<Option<i32>>) };
+   |                               ++                     +
+
+error[E0308]: mismatched types
+  --> $DIR/unboxing-needing-parenthases-issue-132924.rs:12:39
+   |
+LL |     let test: Option<i32> = if true { x as Box<Option<i32>> } else { None };
+   |                                       ^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Box<Option<i32>>`
+   |
+   = note: expected enum `Option<_>`
+            found struct `Box<Option<_>>`
+help: consider unboxing the value
+   |
+LL |     let test: Option<i32> = if true { *(x as Box<Option<i32>>) } else { None };
+   |                                       ++                     +
+
+error[E0308]: mismatched types
+  --> $DIR/unboxing-needing-parenthases-issue-132924.rs:16:29
+   |
+LL |     let test: Option<i32> = x as std::rc::Rc<Option<i32>>;
+   |               -----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Rc<Option<i32>>`
+   |               |
+   |               expected due to this
+   |
+   = note: expected enum `Option<_>`
+            found struct `Rc<Option<_>>`
+help: consider dereferencing the type
+   |
+LL |     let test: Option<i32> = *(x as std::rc::Rc<Option<i32>>);
+   |                             ++                             +
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/confuse-field-and-method/issue-18343.stderr b/tests/ui/confuse-field-and-method/issue-18343.stderr
index a51fd4f02aa..e50c971d837 100644
--- a/tests/ui/confuse-field-and-method/issue-18343.stderr
+++ b/tests/ui/confuse-field-and-method/issue-18343.stderr
@@ -7,7 +7,7 @@ LL | struct Obj<F> where F: FnMut() -> u32 {
 LL |     o.closure();
    |       ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the closure stored in `closure`, surround the field access with parentheses
    |
 LL |     (o.closure)();
    |     +         +
diff --git a/tests/ui/confuse-field-and-method/issue-2392.stderr b/tests/ui/confuse-field-and-method/issue-2392.stderr
index 440fbb27c00..77930de44a7 100644
--- a/tests/ui/confuse-field-and-method/issue-2392.stderr
+++ b/tests/ui/confuse-field-and-method/issue-2392.stderr
@@ -7,7 +7,7 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
 LL |     o_closure.closure();
    |               ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the closure stored in `closure`, surround the field access with parentheses
    |
 LL |     (o_closure.closure)();
    |     +                 +
@@ -46,7 +46,7 @@ LL | struct BoxedObj {
 LL |     boxed_fn.boxed_closure();
    |              ^^^^^^^^^^^^^ field, not a method
    |
-help: to call the function stored in `boxed_closure`, surround the field access with parentheses
+help: to call the trait object stored in `boxed_closure`, surround the field access with parentheses
    |
 LL |     (boxed_fn.boxed_closure)();
    |     +                      +
@@ -60,7 +60,7 @@ LL | struct BoxedObj {
 LL |     boxed_closure.boxed_closure();
    |                   ^^^^^^^^^^^^^ field, not a method
    |
-help: to call the function stored in `boxed_closure`, surround the field access with parentheses
+help: to call the trait object stored in `boxed_closure`, surround the field access with parentheses
    |
 LL |     (boxed_closure.boxed_closure)();
    |     +                           +
@@ -99,7 +99,7 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
 LL |     check_expression().closure();
    |                        ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the trait object stored in `closure`, surround the field access with parentheses
    |
 LL |     (check_expression().closure)();
    |     +                          +
@@ -113,7 +113,7 @@ LL | struct FuncContainer {
 LL |             (*self.container).f1(1);
    |                               ^^ field, not a method
    |
-help: to call the function stored in `f1`, surround the field access with parentheses
+help: to call the function pointer stored in `f1`, surround the field access with parentheses
    |
 LL |             ((*self.container).f1)(1);
    |             +                    +
@@ -127,7 +127,7 @@ LL | struct FuncContainer {
 LL |             (*self.container).f2(1);
    |                               ^^ field, not a method
    |
-help: to call the function stored in `f2`, surround the field access with parentheses
+help: to call the function pointer stored in `f2`, surround the field access with parentheses
    |
 LL |             ((*self.container).f2)(1);
    |             +                    +
@@ -141,7 +141,7 @@ LL | struct FuncContainer {
 LL |             (*self.container).f3(1);
    |                               ^^ field, not a method
    |
-help: to call the function stored in `f3`, surround the field access with parentheses
+help: to call the function pointer stored in `f3`, surround the field access with parentheses
    |
 LL |             ((*self.container).f3)(1);
    |             +                    +
diff --git a/tests/ui/confuse-field-and-method/issue-32128.stderr b/tests/ui/confuse-field-and-method/issue-32128.stderr
index 3d860d8c85a..aaec15a41dc 100644
--- a/tests/ui/confuse-field-and-method/issue-32128.stderr
+++ b/tests/ui/confuse-field-and-method/issue-32128.stderr
@@ -7,7 +7,7 @@ LL | struct Example {
 LL |     demo.example(1);
    |          ^^^^^^^ field, not a method
    |
-help: to call the function stored in `example`, surround the field access with parentheses
+help: to call the trait object stored in `example`, surround the field access with parentheses
    |
 LL |     (demo.example)(1);
    |     +            +
diff --git a/tests/ui/confuse-field-and-method/issue-33784.stderr b/tests/ui/confuse-field-and-method/issue-33784.stderr
index 8acd1f8ff1e..59a6f4fccd8 100644
--- a/tests/ui/confuse-field-and-method/issue-33784.stderr
+++ b/tests/ui/confuse-field-and-method/issue-33784.stderr
@@ -4,7 +4,7 @@ error[E0599]: no method named `closure` found for reference `&Obj<{closure@$DIR/
 LL |     p.closure();
    |       ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the closure stored in `closure`, surround the field access with parentheses
    |
 LL |     (p.closure)();
    |     +         +
@@ -19,7 +19,7 @@ error[E0599]: no method named `fn_ptr` found for reference `&&Obj<{closure@$DIR/
 LL |     q.fn_ptr();
    |       ^^^^^^ field, not a method
    |
-help: to call the function stored in `fn_ptr`, surround the field access with parentheses
+help: to call the function pointer stored in `fn_ptr`, surround the field access with parentheses
    |
 LL |     (q.fn_ptr)();
    |     +        +
@@ -30,7 +30,7 @@ error[E0599]: no method named `c_fn_ptr` found for reference `&D` in the current
 LL |     s.c_fn_ptr();
    |       ^^^^^^^^ field, not a method
    |
-help: to call the function stored in `c_fn_ptr`, surround the field access with parentheses
+help: to call the function pointer stored in `c_fn_ptr`, surround the field access with parentheses
    |
 LL |     (s.c_fn_ptr)();
    |     +          +
diff --git a/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs b/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs
new file mode 100644
index 00000000000..7ae5567bdc5
--- /dev/null
+++ b/tests/ui/const-generics/auxiliary/xcrate-const-ctor-a.rs
@@ -0,0 +1,6 @@
+#![feature(adt_const_params)]
+
+use std::marker::ConstParamTy;
+
+#[derive(Eq, PartialEq, ConstParamTy)]
+pub struct Foo;
diff --git a/tests/ui/const-generics/using-static-as-const-arg.rs b/tests/ui/const-generics/using-static-as-const-arg.rs
new file mode 100644
index 00000000000..2e8a2a14484
--- /dev/null
+++ b/tests/ui/const-generics/using-static-as-const-arg.rs
@@ -0,0 +1,7 @@
+//@ check-pass
+
+pub static STATIC: u32 = 0;
+pub struct Foo<const N: u32>;
+pub const FOO: Foo<{STATIC}> = Foo;
+
+fn main() {}
diff --git a/tests/ui/const-generics/xcrate-const-ctor-b.rs b/tests/ui/const-generics/xcrate-const-ctor-b.rs
new file mode 100644
index 00000000000..dce2e43b316
--- /dev/null
+++ b/tests/ui/const-generics/xcrate-const-ctor-b.rs
@@ -0,0 +1,15 @@
+//@ check-pass
+//@ aux-build:xcrate-const-ctor-a.rs
+
+#![feature(adt_const_params)]
+
+extern crate xcrate_const_ctor_a;
+use xcrate_const_ctor_a::Foo;
+
+fn bar<const N: Foo>() {}
+
+fn baz() {
+    bar::<{ Foo }>();
+}
+
+fn main() {}
diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs
index 61bdf57ffdb..759d2e8b2ed 100644
--- a/tests/ui/consts/const-pattern-irrefutable.rs
+++ b/tests/ui/consts/const-pattern-irrefutable.rs
@@ -1,28 +1,43 @@
 mod foo {
     pub const b: u8 = 2;
-    pub const d: u8 = 2;
+    //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
+    pub const d: (u8, u8) = (2, 1);
+    //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 }
 
 use foo::b as c;
 use foo::d;
 
 const a: u8 = 2;
+//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+
+#[derive(PartialEq)]
+struct S {
+    foo: u8,
+}
+
+const e: S = S {
+    foo: 0,
+};
 
 fn main() {
     let a = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     let c = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
-    let d = 4;
+    let d = (4, 4);
     //~^ ERROR refutable pattern in local binding
-    //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+    //~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
+    //~| HELP introduce a variable instead
+    let e = S {
+    //~^ ERROR refutable pattern in local binding
+    //~| pattern `S { foo: 1_u8..=u8::MAX }` not covered
     //~| HELP introduce a variable instead
+        foo: 1,
+    };
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index 2aed68bdd64..afb67a3a118 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -1,45 +1,76 @@
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:12:9
+  --> $DIR/const-pattern-irrefutable.rs:24:9
    |
+LL | const a: u8 = 2;
+   | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+...
 LL |     let a = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `a_var`
+   |         ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
+help: introduce a variable instead
+   |
+LL |     let a_var = 4;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:17:9
+  --> $DIR/const-pattern-irrefutable.rs:28:9
    |
+LL |     pub const b: u8 = 2;
+   |     --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
+...
 LL |     let c = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `c_var`
+   |         ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
+help: introduce a variable instead
+   |
+LL |     let b_var = 4;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:22:9
+  --> $DIR/const-pattern-irrefutable.rs:32:9
    |
-LL |     let d = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `d_var`
+LL |     pub const d: (u8, u8) = (2, 1);
+   |     --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+...
+LL |     let d = (4, 4);
+   |         ^ patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `u8`
+   = note: the matched value is of type `(u8, u8)`
+help: introduce a variable instead
+   |
+LL |     let d_var = (4, 4);
+   |         ~~~~~
+
+error[E0005]: refutable pattern in local binding
+  --> $DIR/const-pattern-irrefutable.rs:36:9
+   |
+LL | const e: S = S {
+   | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable
+...
+LL |     let e = S {
+   |         ^ pattern `S { foo: 1_u8..=u8::MAX }` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `S` defined here
+  --> $DIR/const-pattern-irrefutable.rs:15:8
+   |
+LL | struct S {
+   |        ^
+   = note: the matched value is of type `S`
+help: introduce a variable instead
+   |
+LL |     let e_var = S {
+   |         ~~~~~
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/consts/const-ptr-is-null.rs b/tests/ui/consts/const-ptr-is-null.rs
index 82c293c0ad6..92cf87a9782 100644
--- a/tests/ui/consts/const-ptr-is-null.rs
+++ b/tests/ui/consts/const-ptr-is-null.rs
@@ -1,4 +1,3 @@
-#![feature(const_ptr_is_null)]
 use std::ptr;
 
 const IS_NULL: () = {
diff --git a/tests/ui/consts/const-ptr-is-null.stderr b/tests/ui/consts/const-ptr-is-null.stderr
index 5fd35142818..f71b3752772 100644
--- a/tests/ui/consts/const-ptr-is-null.stderr
+++ b/tests/ui/consts/const-ptr-is-null.stderr
@@ -8,7 +8,7 @@ note: inside `std::ptr::const_ptr::<impl *const T>::is_null::compiletime`
 note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `MAYBE_NULL`
-  --> $DIR/const-ptr-is-null.rs:17:14
+  --> $DIR/const-ptr-is-null.rs:16:14
    |
 LL |     assert!(!ptr.wrapping_sub(512).is_null());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr
index 8b61b0904a9..dfca04bef07 100644
--- a/tests/ui/consts/const-unstable-intrinsic.stderr
+++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -74,7 +74,7 @@ error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable
 LL |     unsafe { copy(src, dst, count) }
    |              ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval)
+   = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
 
 error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
   --> $DIR/const-unstable-intrinsic.rs:61:9
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
index bd61f43727b..c73d1f05900 100644
--- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match &[][..] {
    |           ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         E_SL => {}
+   |         ---- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `E_SL`
    |
    = note: the matched value is of type `&[E]`
+note: constant `E_SL` defined here
+  --> $DIR/incomplete-slice.rs:6:1
+   |
+LL | const E_SL: &[E] = &[E::A];
+   | ^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         E_SL_var => {}
+   |             ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E_SL => {},
diff --git a/tests/ui/consts/is_val_statically_known.rs b/tests/ui/consts/is_val_statically_known.rs
index a9059817bcc..d55910d32d3 100644
--- a/tests/ui/consts/is_val_statically_known.rs
+++ b/tests/ui/consts/is_val_statically_known.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 
-#![feature(core_intrinsics, is_val_statically_known)]
+#![feature(core_intrinsics)]
 
 use std::intrinsics::is_val_statically_known;
 
diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs
index 51811b14203..429fa060521 100644
--- a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs
+++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -Zforce-unstable-if-unmarked
 //@ edition: 2021
-#![feature(const_async_blocks, rustc_attrs, rustc_private)]
+#![feature(const_async_blocks, rustc_attrs)]
 
 pub const fn not_stably_const() {
     // We need to do something const-unstable here.
diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs
new file mode 100644
index 00000000000..b923a768cbf
--- /dev/null
+++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs
@@ -0,0 +1,12 @@
+//! Ensure we do not ICE when a promoted fails to evaluate due to running out of memory.
+//! Also see <https://github.com/rust-lang/rust/issues/130687>.
+
+// Needs the max type size to be much bigger than the RAM people typically have.
+//@ only-64bit
+
+pub struct Data([u8; (1 << 47) - 1]);
+const _: &'static Data = &Data([0; (1 << 47) - 1]);
+//~^ERROR: evaluation of constant value failed
+//~| tried to allocate more memory than available to compiler
+
+fn main() {}
diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr
new file mode 100644
index 00000000000..50e920f05f9
--- /dev/null
+++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:32
+   |
+LL | const _: &'static Data = &Data([0; (1 << 47) - 1]);
+   |                                ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler
+
+note: erroneous constant encountered
+  --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:26
+   |
+LL | const _: &'static Data = &Data([0; (1 << 47) - 1]);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs
index bbf13802312..8b41f5718e8 100644
--- a/tests/ui/consts/ptr_is_null.rs
+++ b/tests/ui/consts/ptr_is_null.rs
@@ -1,7 +1,6 @@
 //@ compile-flags: --crate-type=lib
 //@ check-pass
 
-#![feature(const_ptr_is_null)]
 #![allow(useless_ptr_null_checks)]
 
 const FOO: &usize = &42;
diff --git a/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs
new file mode 100644
index 00000000000..32ef849f47e
--- /dev/null
+++ b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-1.rs
@@ -0,0 +1,4124 @@
+//@ check-pass
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline
+//@ ignore-msvc
+// ignore-tidy-filelength
+
+#[derive(Default)]
+struct Something {}
+
+#[collapse_debuginfo(yes)]
+macro_rules! collapsed_macro {
+    ($code:expr) => {
+        // Important to use a function here, so it can be inlined
+        // at the MIR stage.
+        Something::default()
+    }
+}
+
+fn collapsed_debuginfo() {
+    // LLVM allows 12 bits for encoding discriminators, so 4096+1 calls to a
+    // MIR-inlined function will exhaust it. But because we're using
+    // collapse_debuginfo(yes) for this macro, we shouldn't need discriminators
+    // at all.
+    collapsed_macro!(1);
+    collapsed_macro!(2);
+    collapsed_macro!(3);
+    collapsed_macro!(4);
+    collapsed_macro!(5);
+    collapsed_macro!(6);
+    collapsed_macro!(7);
+    collapsed_macro!(8);
+    collapsed_macro!(9);
+    collapsed_macro!(10);
+    collapsed_macro!(11);
+    collapsed_macro!(12);
+    collapsed_macro!(13);
+    collapsed_macro!(14);
+    collapsed_macro!(15);
+    collapsed_macro!(16);
+    collapsed_macro!(17);
+    collapsed_macro!(18);
+    collapsed_macro!(19);
+    collapsed_macro!(20);
+    collapsed_macro!(21);
+    collapsed_macro!(22);
+    collapsed_macro!(23);
+    collapsed_macro!(24);
+    collapsed_macro!(25);
+    collapsed_macro!(26);
+    collapsed_macro!(27);
+    collapsed_macro!(28);
+    collapsed_macro!(29);
+    collapsed_macro!(30);
+    collapsed_macro!(31);
+    collapsed_macro!(32);
+    collapsed_macro!(33);
+    collapsed_macro!(34);
+    collapsed_macro!(35);
+    collapsed_macro!(36);
+    collapsed_macro!(37);
+    collapsed_macro!(38);
+    collapsed_macro!(39);
+    collapsed_macro!(40);
+    collapsed_macro!(41);
+    collapsed_macro!(42);
+    collapsed_macro!(43);
+    collapsed_macro!(44);
+    collapsed_macro!(45);
+    collapsed_macro!(46);
+    collapsed_macro!(47);
+    collapsed_macro!(48);
+    collapsed_macro!(49);
+    collapsed_macro!(50);
+    collapsed_macro!(51);
+    collapsed_macro!(52);
+    collapsed_macro!(53);
+    collapsed_macro!(54);
+    collapsed_macro!(55);
+    collapsed_macro!(56);
+    collapsed_macro!(57);
+    collapsed_macro!(58);
+    collapsed_macro!(59);
+    collapsed_macro!(60);
+    collapsed_macro!(61);
+    collapsed_macro!(62);
+    collapsed_macro!(63);
+    collapsed_macro!(64);
+    collapsed_macro!(65);
+    collapsed_macro!(66);
+    collapsed_macro!(67);
+    collapsed_macro!(68);
+    collapsed_macro!(69);
+    collapsed_macro!(70);
+    collapsed_macro!(71);
+    collapsed_macro!(72);
+    collapsed_macro!(73);
+    collapsed_macro!(74);
+    collapsed_macro!(75);
+    collapsed_macro!(76);
+    collapsed_macro!(77);
+    collapsed_macro!(78);
+    collapsed_macro!(79);
+    collapsed_macro!(80);
+    collapsed_macro!(81);
+    collapsed_macro!(82);
+    collapsed_macro!(83);
+    collapsed_macro!(84);
+    collapsed_macro!(85);
+    collapsed_macro!(86);
+    collapsed_macro!(87);
+    collapsed_macro!(88);
+    collapsed_macro!(89);
+    collapsed_macro!(90);
+    collapsed_macro!(91);
+    collapsed_macro!(92);
+    collapsed_macro!(93);
+    collapsed_macro!(94);
+    collapsed_macro!(95);
+    collapsed_macro!(96);
+    collapsed_macro!(97);
+    collapsed_macro!(98);
+    collapsed_macro!(99);
+    collapsed_macro!(100);
+    collapsed_macro!(101);
+    collapsed_macro!(102);
+    collapsed_macro!(103);
+    collapsed_macro!(104);
+    collapsed_macro!(105);
+    collapsed_macro!(106);
+    collapsed_macro!(107);
+    collapsed_macro!(108);
+    collapsed_macro!(109);
+    collapsed_macro!(110);
+    collapsed_macro!(111);
+    collapsed_macro!(112);
+    collapsed_macro!(113);
+    collapsed_macro!(114);
+    collapsed_macro!(115);
+    collapsed_macro!(116);
+    collapsed_macro!(117);
+    collapsed_macro!(118);
+    collapsed_macro!(119);
+    collapsed_macro!(120);
+    collapsed_macro!(121);
+    collapsed_macro!(122);
+    collapsed_macro!(123);
+    collapsed_macro!(124);
+    collapsed_macro!(125);
+    collapsed_macro!(126);
+    collapsed_macro!(127);
+    collapsed_macro!(128);
+    collapsed_macro!(129);
+    collapsed_macro!(130);
+    collapsed_macro!(131);
+    collapsed_macro!(132);
+    collapsed_macro!(133);
+    collapsed_macro!(134);
+    collapsed_macro!(135);
+    collapsed_macro!(136);
+    collapsed_macro!(137);
+    collapsed_macro!(138);
+    collapsed_macro!(139);
+    collapsed_macro!(140);
+    collapsed_macro!(141);
+    collapsed_macro!(142);
+    collapsed_macro!(143);
+    collapsed_macro!(144);
+    collapsed_macro!(145);
+    collapsed_macro!(146);
+    collapsed_macro!(147);
+    collapsed_macro!(148);
+    collapsed_macro!(149);
+    collapsed_macro!(150);
+    collapsed_macro!(151);
+    collapsed_macro!(152);
+    collapsed_macro!(153);
+    collapsed_macro!(154);
+    collapsed_macro!(155);
+    collapsed_macro!(156);
+    collapsed_macro!(157);
+    collapsed_macro!(158);
+    collapsed_macro!(159);
+    collapsed_macro!(160);
+    collapsed_macro!(161);
+    collapsed_macro!(162);
+    collapsed_macro!(163);
+    collapsed_macro!(164);
+    collapsed_macro!(165);
+    collapsed_macro!(166);
+    collapsed_macro!(167);
+    collapsed_macro!(168);
+    collapsed_macro!(169);
+    collapsed_macro!(170);
+    collapsed_macro!(171);
+    collapsed_macro!(172);
+    collapsed_macro!(173);
+    collapsed_macro!(174);
+    collapsed_macro!(175);
+    collapsed_macro!(176);
+    collapsed_macro!(177);
+    collapsed_macro!(178);
+    collapsed_macro!(179);
+    collapsed_macro!(180);
+    collapsed_macro!(181);
+    collapsed_macro!(182);
+    collapsed_macro!(183);
+    collapsed_macro!(184);
+    collapsed_macro!(185);
+    collapsed_macro!(186);
+    collapsed_macro!(187);
+    collapsed_macro!(188);
+    collapsed_macro!(189);
+    collapsed_macro!(190);
+    collapsed_macro!(191);
+    collapsed_macro!(192);
+    collapsed_macro!(193);
+    collapsed_macro!(194);
+    collapsed_macro!(195);
+    collapsed_macro!(196);
+    collapsed_macro!(197);
+    collapsed_macro!(198);
+    collapsed_macro!(199);
+    collapsed_macro!(200);
+    collapsed_macro!(201);
+    collapsed_macro!(202);
+    collapsed_macro!(203);
+    collapsed_macro!(204);
+    collapsed_macro!(205);
+    collapsed_macro!(206);
+    collapsed_macro!(207);
+    collapsed_macro!(208);
+    collapsed_macro!(209);
+    collapsed_macro!(210);
+    collapsed_macro!(211);
+    collapsed_macro!(212);
+    collapsed_macro!(213);
+    collapsed_macro!(214);
+    collapsed_macro!(215);
+    collapsed_macro!(216);
+    collapsed_macro!(217);
+    collapsed_macro!(218);
+    collapsed_macro!(219);
+    collapsed_macro!(220);
+    collapsed_macro!(221);
+    collapsed_macro!(222);
+    collapsed_macro!(223);
+    collapsed_macro!(224);
+    collapsed_macro!(225);
+    collapsed_macro!(226);
+    collapsed_macro!(227);
+    collapsed_macro!(228);
+    collapsed_macro!(229);
+    collapsed_macro!(230);
+    collapsed_macro!(231);
+    collapsed_macro!(232);
+    collapsed_macro!(233);
+    collapsed_macro!(234);
+    collapsed_macro!(235);
+    collapsed_macro!(236);
+    collapsed_macro!(237);
+    collapsed_macro!(238);
+    collapsed_macro!(239);
+    collapsed_macro!(240);
+    collapsed_macro!(241);
+    collapsed_macro!(242);
+    collapsed_macro!(243);
+    collapsed_macro!(244);
+    collapsed_macro!(245);
+    collapsed_macro!(246);
+    collapsed_macro!(247);
+    collapsed_macro!(248);
+    collapsed_macro!(249);
+    collapsed_macro!(250);
+    collapsed_macro!(251);
+    collapsed_macro!(252);
+    collapsed_macro!(253);
+    collapsed_macro!(254);
+    collapsed_macro!(255);
+    collapsed_macro!(256);
+    collapsed_macro!(257);
+    collapsed_macro!(258);
+    collapsed_macro!(259);
+    collapsed_macro!(260);
+    collapsed_macro!(261);
+    collapsed_macro!(262);
+    collapsed_macro!(263);
+    collapsed_macro!(264);
+    collapsed_macro!(265);
+    collapsed_macro!(266);
+    collapsed_macro!(267);
+    collapsed_macro!(268);
+    collapsed_macro!(269);
+    collapsed_macro!(270);
+    collapsed_macro!(271);
+    collapsed_macro!(272);
+    collapsed_macro!(273);
+    collapsed_macro!(274);
+    collapsed_macro!(275);
+    collapsed_macro!(276);
+    collapsed_macro!(277);
+    collapsed_macro!(278);
+    collapsed_macro!(279);
+    collapsed_macro!(280);
+    collapsed_macro!(281);
+    collapsed_macro!(282);
+    collapsed_macro!(283);
+    collapsed_macro!(284);
+    collapsed_macro!(285);
+    collapsed_macro!(286);
+    collapsed_macro!(287);
+    collapsed_macro!(288);
+    collapsed_macro!(289);
+    collapsed_macro!(290);
+    collapsed_macro!(291);
+    collapsed_macro!(292);
+    collapsed_macro!(293);
+    collapsed_macro!(294);
+    collapsed_macro!(295);
+    collapsed_macro!(296);
+    collapsed_macro!(297);
+    collapsed_macro!(298);
+    collapsed_macro!(299);
+    collapsed_macro!(300);
+    collapsed_macro!(301);
+    collapsed_macro!(302);
+    collapsed_macro!(303);
+    collapsed_macro!(304);
+    collapsed_macro!(305);
+    collapsed_macro!(306);
+    collapsed_macro!(307);
+    collapsed_macro!(308);
+    collapsed_macro!(309);
+    collapsed_macro!(310);
+    collapsed_macro!(311);
+    collapsed_macro!(312);
+    collapsed_macro!(313);
+    collapsed_macro!(314);
+    collapsed_macro!(315);
+    collapsed_macro!(316);
+    collapsed_macro!(317);
+    collapsed_macro!(318);
+    collapsed_macro!(319);
+    collapsed_macro!(320);
+    collapsed_macro!(321);
+    collapsed_macro!(322);
+    collapsed_macro!(323);
+    collapsed_macro!(324);
+    collapsed_macro!(325);
+    collapsed_macro!(326);
+    collapsed_macro!(327);
+    collapsed_macro!(328);
+    collapsed_macro!(329);
+    collapsed_macro!(330);
+    collapsed_macro!(331);
+    collapsed_macro!(332);
+    collapsed_macro!(333);
+    collapsed_macro!(334);
+    collapsed_macro!(335);
+    collapsed_macro!(336);
+    collapsed_macro!(337);
+    collapsed_macro!(338);
+    collapsed_macro!(339);
+    collapsed_macro!(340);
+    collapsed_macro!(341);
+    collapsed_macro!(342);
+    collapsed_macro!(343);
+    collapsed_macro!(344);
+    collapsed_macro!(345);
+    collapsed_macro!(346);
+    collapsed_macro!(347);
+    collapsed_macro!(348);
+    collapsed_macro!(349);
+    collapsed_macro!(350);
+    collapsed_macro!(351);
+    collapsed_macro!(352);
+    collapsed_macro!(353);
+    collapsed_macro!(354);
+    collapsed_macro!(355);
+    collapsed_macro!(356);
+    collapsed_macro!(357);
+    collapsed_macro!(358);
+    collapsed_macro!(359);
+    collapsed_macro!(360);
+    collapsed_macro!(361);
+    collapsed_macro!(362);
+    collapsed_macro!(363);
+    collapsed_macro!(364);
+    collapsed_macro!(365);
+    collapsed_macro!(366);
+    collapsed_macro!(367);
+    collapsed_macro!(368);
+    collapsed_macro!(369);
+    collapsed_macro!(370);
+    collapsed_macro!(371);
+    collapsed_macro!(372);
+    collapsed_macro!(373);
+    collapsed_macro!(374);
+    collapsed_macro!(375);
+    collapsed_macro!(376);
+    collapsed_macro!(377);
+    collapsed_macro!(378);
+    collapsed_macro!(379);
+    collapsed_macro!(380);
+    collapsed_macro!(381);
+    collapsed_macro!(382);
+    collapsed_macro!(383);
+    collapsed_macro!(384);
+    collapsed_macro!(385);
+    collapsed_macro!(386);
+    collapsed_macro!(387);
+    collapsed_macro!(388);
+    collapsed_macro!(389);
+    collapsed_macro!(390);
+    collapsed_macro!(391);
+    collapsed_macro!(392);
+    collapsed_macro!(393);
+    collapsed_macro!(394);
+    collapsed_macro!(395);
+    collapsed_macro!(396);
+    collapsed_macro!(397);
+    collapsed_macro!(398);
+    collapsed_macro!(399);
+    collapsed_macro!(400);
+    collapsed_macro!(401);
+    collapsed_macro!(402);
+    collapsed_macro!(403);
+    collapsed_macro!(404);
+    collapsed_macro!(405);
+    collapsed_macro!(406);
+    collapsed_macro!(407);
+    collapsed_macro!(408);
+    collapsed_macro!(409);
+    collapsed_macro!(410);
+    collapsed_macro!(411);
+    collapsed_macro!(412);
+    collapsed_macro!(413);
+    collapsed_macro!(414);
+    collapsed_macro!(415);
+    collapsed_macro!(416);
+    collapsed_macro!(417);
+    collapsed_macro!(418);
+    collapsed_macro!(419);
+    collapsed_macro!(420);
+    collapsed_macro!(421);
+    collapsed_macro!(422);
+    collapsed_macro!(423);
+    collapsed_macro!(424);
+    collapsed_macro!(425);
+    collapsed_macro!(426);
+    collapsed_macro!(427);
+    collapsed_macro!(428);
+    collapsed_macro!(429);
+    collapsed_macro!(430);
+    collapsed_macro!(431);
+    collapsed_macro!(432);
+    collapsed_macro!(433);
+    collapsed_macro!(434);
+    collapsed_macro!(435);
+    collapsed_macro!(436);
+    collapsed_macro!(437);
+    collapsed_macro!(438);
+    collapsed_macro!(439);
+    collapsed_macro!(440);
+    collapsed_macro!(441);
+    collapsed_macro!(442);
+    collapsed_macro!(443);
+    collapsed_macro!(444);
+    collapsed_macro!(445);
+    collapsed_macro!(446);
+    collapsed_macro!(447);
+    collapsed_macro!(448);
+    collapsed_macro!(449);
+    collapsed_macro!(450);
+    collapsed_macro!(451);
+    collapsed_macro!(452);
+    collapsed_macro!(453);
+    collapsed_macro!(454);
+    collapsed_macro!(455);
+    collapsed_macro!(456);
+    collapsed_macro!(457);
+    collapsed_macro!(458);
+    collapsed_macro!(459);
+    collapsed_macro!(460);
+    collapsed_macro!(461);
+    collapsed_macro!(462);
+    collapsed_macro!(463);
+    collapsed_macro!(464);
+    collapsed_macro!(465);
+    collapsed_macro!(466);
+    collapsed_macro!(467);
+    collapsed_macro!(468);
+    collapsed_macro!(469);
+    collapsed_macro!(470);
+    collapsed_macro!(471);
+    collapsed_macro!(472);
+    collapsed_macro!(473);
+    collapsed_macro!(474);
+    collapsed_macro!(475);
+    collapsed_macro!(476);
+    collapsed_macro!(477);
+    collapsed_macro!(478);
+    collapsed_macro!(479);
+    collapsed_macro!(480);
+    collapsed_macro!(481);
+    collapsed_macro!(482);
+    collapsed_macro!(483);
+    collapsed_macro!(484);
+    collapsed_macro!(485);
+    collapsed_macro!(486);
+    collapsed_macro!(487);
+    collapsed_macro!(488);
+    collapsed_macro!(489);
+    collapsed_macro!(490);
+    collapsed_macro!(491);
+    collapsed_macro!(492);
+    collapsed_macro!(493);
+    collapsed_macro!(494);
+    collapsed_macro!(495);
+    collapsed_macro!(496);
+    collapsed_macro!(497);
+    collapsed_macro!(498);
+    collapsed_macro!(499);
+    collapsed_macro!(500);
+    collapsed_macro!(501);
+    collapsed_macro!(502);
+    collapsed_macro!(503);
+    collapsed_macro!(504);
+    collapsed_macro!(505);
+    collapsed_macro!(506);
+    collapsed_macro!(507);
+    collapsed_macro!(508);
+    collapsed_macro!(509);
+    collapsed_macro!(510);
+    collapsed_macro!(511);
+    collapsed_macro!(512);
+    collapsed_macro!(513);
+    collapsed_macro!(514);
+    collapsed_macro!(515);
+    collapsed_macro!(516);
+    collapsed_macro!(517);
+    collapsed_macro!(518);
+    collapsed_macro!(519);
+    collapsed_macro!(520);
+    collapsed_macro!(521);
+    collapsed_macro!(522);
+    collapsed_macro!(523);
+    collapsed_macro!(524);
+    collapsed_macro!(525);
+    collapsed_macro!(526);
+    collapsed_macro!(527);
+    collapsed_macro!(528);
+    collapsed_macro!(529);
+    collapsed_macro!(530);
+    collapsed_macro!(531);
+    collapsed_macro!(532);
+    collapsed_macro!(533);
+    collapsed_macro!(534);
+    collapsed_macro!(535);
+    collapsed_macro!(536);
+    collapsed_macro!(537);
+    collapsed_macro!(538);
+    collapsed_macro!(539);
+    collapsed_macro!(540);
+    collapsed_macro!(541);
+    collapsed_macro!(542);
+    collapsed_macro!(543);
+    collapsed_macro!(544);
+    collapsed_macro!(545);
+    collapsed_macro!(546);
+    collapsed_macro!(547);
+    collapsed_macro!(548);
+    collapsed_macro!(549);
+    collapsed_macro!(550);
+    collapsed_macro!(551);
+    collapsed_macro!(552);
+    collapsed_macro!(553);
+    collapsed_macro!(554);
+    collapsed_macro!(555);
+    collapsed_macro!(556);
+    collapsed_macro!(557);
+    collapsed_macro!(558);
+    collapsed_macro!(559);
+    collapsed_macro!(560);
+    collapsed_macro!(561);
+    collapsed_macro!(562);
+    collapsed_macro!(563);
+    collapsed_macro!(564);
+    collapsed_macro!(565);
+    collapsed_macro!(566);
+    collapsed_macro!(567);
+    collapsed_macro!(568);
+    collapsed_macro!(569);
+    collapsed_macro!(570);
+    collapsed_macro!(571);
+    collapsed_macro!(572);
+    collapsed_macro!(573);
+    collapsed_macro!(574);
+    collapsed_macro!(575);
+    collapsed_macro!(576);
+    collapsed_macro!(577);
+    collapsed_macro!(578);
+    collapsed_macro!(579);
+    collapsed_macro!(580);
+    collapsed_macro!(581);
+    collapsed_macro!(582);
+    collapsed_macro!(583);
+    collapsed_macro!(584);
+    collapsed_macro!(585);
+    collapsed_macro!(586);
+    collapsed_macro!(587);
+    collapsed_macro!(588);
+    collapsed_macro!(589);
+    collapsed_macro!(590);
+    collapsed_macro!(591);
+    collapsed_macro!(592);
+    collapsed_macro!(593);
+    collapsed_macro!(594);
+    collapsed_macro!(595);
+    collapsed_macro!(596);
+    collapsed_macro!(597);
+    collapsed_macro!(598);
+    collapsed_macro!(599);
+    collapsed_macro!(600);
+    collapsed_macro!(601);
+    collapsed_macro!(602);
+    collapsed_macro!(603);
+    collapsed_macro!(604);
+    collapsed_macro!(605);
+    collapsed_macro!(606);
+    collapsed_macro!(607);
+    collapsed_macro!(608);
+    collapsed_macro!(609);
+    collapsed_macro!(610);
+    collapsed_macro!(611);
+    collapsed_macro!(612);
+    collapsed_macro!(613);
+    collapsed_macro!(614);
+    collapsed_macro!(615);
+    collapsed_macro!(616);
+    collapsed_macro!(617);
+    collapsed_macro!(618);
+    collapsed_macro!(619);
+    collapsed_macro!(620);
+    collapsed_macro!(621);
+    collapsed_macro!(622);
+    collapsed_macro!(623);
+    collapsed_macro!(624);
+    collapsed_macro!(625);
+    collapsed_macro!(626);
+    collapsed_macro!(627);
+    collapsed_macro!(628);
+    collapsed_macro!(629);
+    collapsed_macro!(630);
+    collapsed_macro!(631);
+    collapsed_macro!(632);
+    collapsed_macro!(633);
+    collapsed_macro!(634);
+    collapsed_macro!(635);
+    collapsed_macro!(636);
+    collapsed_macro!(637);
+    collapsed_macro!(638);
+    collapsed_macro!(639);
+    collapsed_macro!(640);
+    collapsed_macro!(641);
+    collapsed_macro!(642);
+    collapsed_macro!(643);
+    collapsed_macro!(644);
+    collapsed_macro!(645);
+    collapsed_macro!(646);
+    collapsed_macro!(647);
+    collapsed_macro!(648);
+    collapsed_macro!(649);
+    collapsed_macro!(650);
+    collapsed_macro!(651);
+    collapsed_macro!(652);
+    collapsed_macro!(653);
+    collapsed_macro!(654);
+    collapsed_macro!(655);
+    collapsed_macro!(656);
+    collapsed_macro!(657);
+    collapsed_macro!(658);
+    collapsed_macro!(659);
+    collapsed_macro!(660);
+    collapsed_macro!(661);
+    collapsed_macro!(662);
+    collapsed_macro!(663);
+    collapsed_macro!(664);
+    collapsed_macro!(665);
+    collapsed_macro!(666);
+    collapsed_macro!(667);
+    collapsed_macro!(668);
+    collapsed_macro!(669);
+    collapsed_macro!(670);
+    collapsed_macro!(671);
+    collapsed_macro!(672);
+    collapsed_macro!(673);
+    collapsed_macro!(674);
+    collapsed_macro!(675);
+    collapsed_macro!(676);
+    collapsed_macro!(677);
+    collapsed_macro!(678);
+    collapsed_macro!(679);
+    collapsed_macro!(680);
+    collapsed_macro!(681);
+    collapsed_macro!(682);
+    collapsed_macro!(683);
+    collapsed_macro!(684);
+    collapsed_macro!(685);
+    collapsed_macro!(686);
+    collapsed_macro!(687);
+    collapsed_macro!(688);
+    collapsed_macro!(689);
+    collapsed_macro!(690);
+    collapsed_macro!(691);
+    collapsed_macro!(692);
+    collapsed_macro!(693);
+    collapsed_macro!(694);
+    collapsed_macro!(695);
+    collapsed_macro!(696);
+    collapsed_macro!(697);
+    collapsed_macro!(698);
+    collapsed_macro!(699);
+    collapsed_macro!(700);
+    collapsed_macro!(701);
+    collapsed_macro!(702);
+    collapsed_macro!(703);
+    collapsed_macro!(704);
+    collapsed_macro!(705);
+    collapsed_macro!(706);
+    collapsed_macro!(707);
+    collapsed_macro!(708);
+    collapsed_macro!(709);
+    collapsed_macro!(710);
+    collapsed_macro!(711);
+    collapsed_macro!(712);
+    collapsed_macro!(713);
+    collapsed_macro!(714);
+    collapsed_macro!(715);
+    collapsed_macro!(716);
+    collapsed_macro!(717);
+    collapsed_macro!(718);
+    collapsed_macro!(719);
+    collapsed_macro!(720);
+    collapsed_macro!(721);
+    collapsed_macro!(722);
+    collapsed_macro!(723);
+    collapsed_macro!(724);
+    collapsed_macro!(725);
+    collapsed_macro!(726);
+    collapsed_macro!(727);
+    collapsed_macro!(728);
+    collapsed_macro!(729);
+    collapsed_macro!(730);
+    collapsed_macro!(731);
+    collapsed_macro!(732);
+    collapsed_macro!(733);
+    collapsed_macro!(734);
+    collapsed_macro!(735);
+    collapsed_macro!(736);
+    collapsed_macro!(737);
+    collapsed_macro!(738);
+    collapsed_macro!(739);
+    collapsed_macro!(740);
+    collapsed_macro!(741);
+    collapsed_macro!(742);
+    collapsed_macro!(743);
+    collapsed_macro!(744);
+    collapsed_macro!(745);
+    collapsed_macro!(746);
+    collapsed_macro!(747);
+    collapsed_macro!(748);
+    collapsed_macro!(749);
+    collapsed_macro!(750);
+    collapsed_macro!(751);
+    collapsed_macro!(752);
+    collapsed_macro!(753);
+    collapsed_macro!(754);
+    collapsed_macro!(755);
+    collapsed_macro!(756);
+    collapsed_macro!(757);
+    collapsed_macro!(758);
+    collapsed_macro!(759);
+    collapsed_macro!(760);
+    collapsed_macro!(761);
+    collapsed_macro!(762);
+    collapsed_macro!(763);
+    collapsed_macro!(764);
+    collapsed_macro!(765);
+    collapsed_macro!(766);
+    collapsed_macro!(767);
+    collapsed_macro!(768);
+    collapsed_macro!(769);
+    collapsed_macro!(770);
+    collapsed_macro!(771);
+    collapsed_macro!(772);
+    collapsed_macro!(773);
+    collapsed_macro!(774);
+    collapsed_macro!(775);
+    collapsed_macro!(776);
+    collapsed_macro!(777);
+    collapsed_macro!(778);
+    collapsed_macro!(779);
+    collapsed_macro!(780);
+    collapsed_macro!(781);
+    collapsed_macro!(782);
+    collapsed_macro!(783);
+    collapsed_macro!(784);
+    collapsed_macro!(785);
+    collapsed_macro!(786);
+    collapsed_macro!(787);
+    collapsed_macro!(788);
+    collapsed_macro!(789);
+    collapsed_macro!(790);
+    collapsed_macro!(791);
+    collapsed_macro!(792);
+    collapsed_macro!(793);
+    collapsed_macro!(794);
+    collapsed_macro!(795);
+    collapsed_macro!(796);
+    collapsed_macro!(797);
+    collapsed_macro!(798);
+    collapsed_macro!(799);
+    collapsed_macro!(800);
+    collapsed_macro!(801);
+    collapsed_macro!(802);
+    collapsed_macro!(803);
+    collapsed_macro!(804);
+    collapsed_macro!(805);
+    collapsed_macro!(806);
+    collapsed_macro!(807);
+    collapsed_macro!(808);
+    collapsed_macro!(809);
+    collapsed_macro!(810);
+    collapsed_macro!(811);
+    collapsed_macro!(812);
+    collapsed_macro!(813);
+    collapsed_macro!(814);
+    collapsed_macro!(815);
+    collapsed_macro!(816);
+    collapsed_macro!(817);
+    collapsed_macro!(818);
+    collapsed_macro!(819);
+    collapsed_macro!(820);
+    collapsed_macro!(821);
+    collapsed_macro!(822);
+    collapsed_macro!(823);
+    collapsed_macro!(824);
+    collapsed_macro!(825);
+    collapsed_macro!(826);
+    collapsed_macro!(827);
+    collapsed_macro!(828);
+    collapsed_macro!(829);
+    collapsed_macro!(830);
+    collapsed_macro!(831);
+    collapsed_macro!(832);
+    collapsed_macro!(833);
+    collapsed_macro!(834);
+    collapsed_macro!(835);
+    collapsed_macro!(836);
+    collapsed_macro!(837);
+    collapsed_macro!(838);
+    collapsed_macro!(839);
+    collapsed_macro!(840);
+    collapsed_macro!(841);
+    collapsed_macro!(842);
+    collapsed_macro!(843);
+    collapsed_macro!(844);
+    collapsed_macro!(845);
+    collapsed_macro!(846);
+    collapsed_macro!(847);
+    collapsed_macro!(848);
+    collapsed_macro!(849);
+    collapsed_macro!(850);
+    collapsed_macro!(851);
+    collapsed_macro!(852);
+    collapsed_macro!(853);
+    collapsed_macro!(854);
+    collapsed_macro!(855);
+    collapsed_macro!(856);
+    collapsed_macro!(857);
+    collapsed_macro!(858);
+    collapsed_macro!(859);
+    collapsed_macro!(860);
+    collapsed_macro!(861);
+    collapsed_macro!(862);
+    collapsed_macro!(863);
+    collapsed_macro!(864);
+    collapsed_macro!(865);
+    collapsed_macro!(866);
+    collapsed_macro!(867);
+    collapsed_macro!(868);
+    collapsed_macro!(869);
+    collapsed_macro!(870);
+    collapsed_macro!(871);
+    collapsed_macro!(872);
+    collapsed_macro!(873);
+    collapsed_macro!(874);
+    collapsed_macro!(875);
+    collapsed_macro!(876);
+    collapsed_macro!(877);
+    collapsed_macro!(878);
+    collapsed_macro!(879);
+    collapsed_macro!(880);
+    collapsed_macro!(881);
+    collapsed_macro!(882);
+    collapsed_macro!(883);
+    collapsed_macro!(884);
+    collapsed_macro!(885);
+    collapsed_macro!(886);
+    collapsed_macro!(887);
+    collapsed_macro!(888);
+    collapsed_macro!(889);
+    collapsed_macro!(890);
+    collapsed_macro!(891);
+    collapsed_macro!(892);
+    collapsed_macro!(893);
+    collapsed_macro!(894);
+    collapsed_macro!(895);
+    collapsed_macro!(896);
+    collapsed_macro!(897);
+    collapsed_macro!(898);
+    collapsed_macro!(899);
+    collapsed_macro!(900);
+    collapsed_macro!(901);
+    collapsed_macro!(902);
+    collapsed_macro!(903);
+    collapsed_macro!(904);
+    collapsed_macro!(905);
+    collapsed_macro!(906);
+    collapsed_macro!(907);
+    collapsed_macro!(908);
+    collapsed_macro!(909);
+    collapsed_macro!(910);
+    collapsed_macro!(911);
+    collapsed_macro!(912);
+    collapsed_macro!(913);
+    collapsed_macro!(914);
+    collapsed_macro!(915);
+    collapsed_macro!(916);
+    collapsed_macro!(917);
+    collapsed_macro!(918);
+    collapsed_macro!(919);
+    collapsed_macro!(920);
+    collapsed_macro!(921);
+    collapsed_macro!(922);
+    collapsed_macro!(923);
+    collapsed_macro!(924);
+    collapsed_macro!(925);
+    collapsed_macro!(926);
+    collapsed_macro!(927);
+    collapsed_macro!(928);
+    collapsed_macro!(929);
+    collapsed_macro!(930);
+    collapsed_macro!(931);
+    collapsed_macro!(932);
+    collapsed_macro!(933);
+    collapsed_macro!(934);
+    collapsed_macro!(935);
+    collapsed_macro!(936);
+    collapsed_macro!(937);
+    collapsed_macro!(938);
+    collapsed_macro!(939);
+    collapsed_macro!(940);
+    collapsed_macro!(941);
+    collapsed_macro!(942);
+    collapsed_macro!(943);
+    collapsed_macro!(944);
+    collapsed_macro!(945);
+    collapsed_macro!(946);
+    collapsed_macro!(947);
+    collapsed_macro!(948);
+    collapsed_macro!(949);
+    collapsed_macro!(950);
+    collapsed_macro!(951);
+    collapsed_macro!(952);
+    collapsed_macro!(953);
+    collapsed_macro!(954);
+    collapsed_macro!(955);
+    collapsed_macro!(956);
+    collapsed_macro!(957);
+    collapsed_macro!(958);
+    collapsed_macro!(959);
+    collapsed_macro!(960);
+    collapsed_macro!(961);
+    collapsed_macro!(962);
+    collapsed_macro!(963);
+    collapsed_macro!(964);
+    collapsed_macro!(965);
+    collapsed_macro!(966);
+    collapsed_macro!(967);
+    collapsed_macro!(968);
+    collapsed_macro!(969);
+    collapsed_macro!(970);
+    collapsed_macro!(971);
+    collapsed_macro!(972);
+    collapsed_macro!(973);
+    collapsed_macro!(974);
+    collapsed_macro!(975);
+    collapsed_macro!(976);
+    collapsed_macro!(977);
+    collapsed_macro!(978);
+    collapsed_macro!(979);
+    collapsed_macro!(980);
+    collapsed_macro!(981);
+    collapsed_macro!(982);
+    collapsed_macro!(983);
+    collapsed_macro!(984);
+    collapsed_macro!(985);
+    collapsed_macro!(986);
+    collapsed_macro!(987);
+    collapsed_macro!(988);
+    collapsed_macro!(989);
+    collapsed_macro!(990);
+    collapsed_macro!(991);
+    collapsed_macro!(992);
+    collapsed_macro!(993);
+    collapsed_macro!(994);
+    collapsed_macro!(995);
+    collapsed_macro!(996);
+    collapsed_macro!(997);
+    collapsed_macro!(998);
+    collapsed_macro!(999);
+    collapsed_macro!(1000);
+    collapsed_macro!(1001);
+    collapsed_macro!(1002);
+    collapsed_macro!(1003);
+    collapsed_macro!(1004);
+    collapsed_macro!(1005);
+    collapsed_macro!(1006);
+    collapsed_macro!(1007);
+    collapsed_macro!(1008);
+    collapsed_macro!(1009);
+    collapsed_macro!(1010);
+    collapsed_macro!(1011);
+    collapsed_macro!(1012);
+    collapsed_macro!(1013);
+    collapsed_macro!(1014);
+    collapsed_macro!(1015);
+    collapsed_macro!(1016);
+    collapsed_macro!(1017);
+    collapsed_macro!(1018);
+    collapsed_macro!(1019);
+    collapsed_macro!(1020);
+    collapsed_macro!(1021);
+    collapsed_macro!(1022);
+    collapsed_macro!(1023);
+    collapsed_macro!(1024);
+    collapsed_macro!(1025);
+    collapsed_macro!(1026);
+    collapsed_macro!(1027);
+    collapsed_macro!(1028);
+    collapsed_macro!(1029);
+    collapsed_macro!(1030);
+    collapsed_macro!(1031);
+    collapsed_macro!(1032);
+    collapsed_macro!(1033);
+    collapsed_macro!(1034);
+    collapsed_macro!(1035);
+    collapsed_macro!(1036);
+    collapsed_macro!(1037);
+    collapsed_macro!(1038);
+    collapsed_macro!(1039);
+    collapsed_macro!(1040);
+    collapsed_macro!(1041);
+    collapsed_macro!(1042);
+    collapsed_macro!(1043);
+    collapsed_macro!(1044);
+    collapsed_macro!(1045);
+    collapsed_macro!(1046);
+    collapsed_macro!(1047);
+    collapsed_macro!(1048);
+    collapsed_macro!(1049);
+    collapsed_macro!(1050);
+    collapsed_macro!(1051);
+    collapsed_macro!(1052);
+    collapsed_macro!(1053);
+    collapsed_macro!(1054);
+    collapsed_macro!(1055);
+    collapsed_macro!(1056);
+    collapsed_macro!(1057);
+    collapsed_macro!(1058);
+    collapsed_macro!(1059);
+    collapsed_macro!(1060);
+    collapsed_macro!(1061);
+    collapsed_macro!(1062);
+    collapsed_macro!(1063);
+    collapsed_macro!(1064);
+    collapsed_macro!(1065);
+    collapsed_macro!(1066);
+    collapsed_macro!(1067);
+    collapsed_macro!(1068);
+    collapsed_macro!(1069);
+    collapsed_macro!(1070);
+    collapsed_macro!(1071);
+    collapsed_macro!(1072);
+    collapsed_macro!(1073);
+    collapsed_macro!(1074);
+    collapsed_macro!(1075);
+    collapsed_macro!(1076);
+    collapsed_macro!(1077);
+    collapsed_macro!(1078);
+    collapsed_macro!(1079);
+    collapsed_macro!(1080);
+    collapsed_macro!(1081);
+    collapsed_macro!(1082);
+    collapsed_macro!(1083);
+    collapsed_macro!(1084);
+    collapsed_macro!(1085);
+    collapsed_macro!(1086);
+    collapsed_macro!(1087);
+    collapsed_macro!(1088);
+    collapsed_macro!(1089);
+    collapsed_macro!(1090);
+    collapsed_macro!(1091);
+    collapsed_macro!(1092);
+    collapsed_macro!(1093);
+    collapsed_macro!(1094);
+    collapsed_macro!(1095);
+    collapsed_macro!(1096);
+    collapsed_macro!(1097);
+    collapsed_macro!(1098);
+    collapsed_macro!(1099);
+    collapsed_macro!(1100);
+    collapsed_macro!(1101);
+    collapsed_macro!(1102);
+    collapsed_macro!(1103);
+    collapsed_macro!(1104);
+    collapsed_macro!(1105);
+    collapsed_macro!(1106);
+    collapsed_macro!(1107);
+    collapsed_macro!(1108);
+    collapsed_macro!(1109);
+    collapsed_macro!(1110);
+    collapsed_macro!(1111);
+    collapsed_macro!(1112);
+    collapsed_macro!(1113);
+    collapsed_macro!(1114);
+    collapsed_macro!(1115);
+    collapsed_macro!(1116);
+    collapsed_macro!(1117);
+    collapsed_macro!(1118);
+    collapsed_macro!(1119);
+    collapsed_macro!(1120);
+    collapsed_macro!(1121);
+    collapsed_macro!(1122);
+    collapsed_macro!(1123);
+    collapsed_macro!(1124);
+    collapsed_macro!(1125);
+    collapsed_macro!(1126);
+    collapsed_macro!(1127);
+    collapsed_macro!(1128);
+    collapsed_macro!(1129);
+    collapsed_macro!(1130);
+    collapsed_macro!(1131);
+    collapsed_macro!(1132);
+    collapsed_macro!(1133);
+    collapsed_macro!(1134);
+    collapsed_macro!(1135);
+    collapsed_macro!(1136);
+    collapsed_macro!(1137);
+    collapsed_macro!(1138);
+    collapsed_macro!(1139);
+    collapsed_macro!(1140);
+    collapsed_macro!(1141);
+    collapsed_macro!(1142);
+    collapsed_macro!(1143);
+    collapsed_macro!(1144);
+    collapsed_macro!(1145);
+    collapsed_macro!(1146);
+    collapsed_macro!(1147);
+    collapsed_macro!(1148);
+    collapsed_macro!(1149);
+    collapsed_macro!(1150);
+    collapsed_macro!(1151);
+    collapsed_macro!(1152);
+    collapsed_macro!(1153);
+    collapsed_macro!(1154);
+    collapsed_macro!(1155);
+    collapsed_macro!(1156);
+    collapsed_macro!(1157);
+    collapsed_macro!(1158);
+    collapsed_macro!(1159);
+    collapsed_macro!(1160);
+    collapsed_macro!(1161);
+    collapsed_macro!(1162);
+    collapsed_macro!(1163);
+    collapsed_macro!(1164);
+    collapsed_macro!(1165);
+    collapsed_macro!(1166);
+    collapsed_macro!(1167);
+    collapsed_macro!(1168);
+    collapsed_macro!(1169);
+    collapsed_macro!(1170);
+    collapsed_macro!(1171);
+    collapsed_macro!(1172);
+    collapsed_macro!(1173);
+    collapsed_macro!(1174);
+    collapsed_macro!(1175);
+    collapsed_macro!(1176);
+    collapsed_macro!(1177);
+    collapsed_macro!(1178);
+    collapsed_macro!(1179);
+    collapsed_macro!(1180);
+    collapsed_macro!(1181);
+    collapsed_macro!(1182);
+    collapsed_macro!(1183);
+    collapsed_macro!(1184);
+    collapsed_macro!(1185);
+    collapsed_macro!(1186);
+    collapsed_macro!(1187);
+    collapsed_macro!(1188);
+    collapsed_macro!(1189);
+    collapsed_macro!(1190);
+    collapsed_macro!(1191);
+    collapsed_macro!(1192);
+    collapsed_macro!(1193);
+    collapsed_macro!(1194);
+    collapsed_macro!(1195);
+    collapsed_macro!(1196);
+    collapsed_macro!(1197);
+    collapsed_macro!(1198);
+    collapsed_macro!(1199);
+    collapsed_macro!(1200);
+    collapsed_macro!(1201);
+    collapsed_macro!(1202);
+    collapsed_macro!(1203);
+    collapsed_macro!(1204);
+    collapsed_macro!(1205);
+    collapsed_macro!(1206);
+    collapsed_macro!(1207);
+    collapsed_macro!(1208);
+    collapsed_macro!(1209);
+    collapsed_macro!(1210);
+    collapsed_macro!(1211);
+    collapsed_macro!(1212);
+    collapsed_macro!(1213);
+    collapsed_macro!(1214);
+    collapsed_macro!(1215);
+    collapsed_macro!(1216);
+    collapsed_macro!(1217);
+    collapsed_macro!(1218);
+    collapsed_macro!(1219);
+    collapsed_macro!(1220);
+    collapsed_macro!(1221);
+    collapsed_macro!(1222);
+    collapsed_macro!(1223);
+    collapsed_macro!(1224);
+    collapsed_macro!(1225);
+    collapsed_macro!(1226);
+    collapsed_macro!(1227);
+    collapsed_macro!(1228);
+    collapsed_macro!(1229);
+    collapsed_macro!(1230);
+    collapsed_macro!(1231);
+    collapsed_macro!(1232);
+    collapsed_macro!(1233);
+    collapsed_macro!(1234);
+    collapsed_macro!(1235);
+    collapsed_macro!(1236);
+    collapsed_macro!(1237);
+    collapsed_macro!(1238);
+    collapsed_macro!(1239);
+    collapsed_macro!(1240);
+    collapsed_macro!(1241);
+    collapsed_macro!(1242);
+    collapsed_macro!(1243);
+    collapsed_macro!(1244);
+    collapsed_macro!(1245);
+    collapsed_macro!(1246);
+    collapsed_macro!(1247);
+    collapsed_macro!(1248);
+    collapsed_macro!(1249);
+    collapsed_macro!(1250);
+    collapsed_macro!(1251);
+    collapsed_macro!(1252);
+    collapsed_macro!(1253);
+    collapsed_macro!(1254);
+    collapsed_macro!(1255);
+    collapsed_macro!(1256);
+    collapsed_macro!(1257);
+    collapsed_macro!(1258);
+    collapsed_macro!(1259);
+    collapsed_macro!(1260);
+    collapsed_macro!(1261);
+    collapsed_macro!(1262);
+    collapsed_macro!(1263);
+    collapsed_macro!(1264);
+    collapsed_macro!(1265);
+    collapsed_macro!(1266);
+    collapsed_macro!(1267);
+    collapsed_macro!(1268);
+    collapsed_macro!(1269);
+    collapsed_macro!(1270);
+    collapsed_macro!(1271);
+    collapsed_macro!(1272);
+    collapsed_macro!(1273);
+    collapsed_macro!(1274);
+    collapsed_macro!(1275);
+    collapsed_macro!(1276);
+    collapsed_macro!(1277);
+    collapsed_macro!(1278);
+    collapsed_macro!(1279);
+    collapsed_macro!(1280);
+    collapsed_macro!(1281);
+    collapsed_macro!(1282);
+    collapsed_macro!(1283);
+    collapsed_macro!(1284);
+    collapsed_macro!(1285);
+    collapsed_macro!(1286);
+    collapsed_macro!(1287);
+    collapsed_macro!(1288);
+    collapsed_macro!(1289);
+    collapsed_macro!(1290);
+    collapsed_macro!(1291);
+    collapsed_macro!(1292);
+    collapsed_macro!(1293);
+    collapsed_macro!(1294);
+    collapsed_macro!(1295);
+    collapsed_macro!(1296);
+    collapsed_macro!(1297);
+    collapsed_macro!(1298);
+    collapsed_macro!(1299);
+    collapsed_macro!(1300);
+    collapsed_macro!(1301);
+    collapsed_macro!(1302);
+    collapsed_macro!(1303);
+    collapsed_macro!(1304);
+    collapsed_macro!(1305);
+    collapsed_macro!(1306);
+    collapsed_macro!(1307);
+    collapsed_macro!(1308);
+    collapsed_macro!(1309);
+    collapsed_macro!(1310);
+    collapsed_macro!(1311);
+    collapsed_macro!(1312);
+    collapsed_macro!(1313);
+    collapsed_macro!(1314);
+    collapsed_macro!(1315);
+    collapsed_macro!(1316);
+    collapsed_macro!(1317);
+    collapsed_macro!(1318);
+    collapsed_macro!(1319);
+    collapsed_macro!(1320);
+    collapsed_macro!(1321);
+    collapsed_macro!(1322);
+    collapsed_macro!(1323);
+    collapsed_macro!(1324);
+    collapsed_macro!(1325);
+    collapsed_macro!(1326);
+    collapsed_macro!(1327);
+    collapsed_macro!(1328);
+    collapsed_macro!(1329);
+    collapsed_macro!(1330);
+    collapsed_macro!(1331);
+    collapsed_macro!(1332);
+    collapsed_macro!(1333);
+    collapsed_macro!(1334);
+    collapsed_macro!(1335);
+    collapsed_macro!(1336);
+    collapsed_macro!(1337);
+    collapsed_macro!(1338);
+    collapsed_macro!(1339);
+    collapsed_macro!(1340);
+    collapsed_macro!(1341);
+    collapsed_macro!(1342);
+    collapsed_macro!(1343);
+    collapsed_macro!(1344);
+    collapsed_macro!(1345);
+    collapsed_macro!(1346);
+    collapsed_macro!(1347);
+    collapsed_macro!(1348);
+    collapsed_macro!(1349);
+    collapsed_macro!(1350);
+    collapsed_macro!(1351);
+    collapsed_macro!(1352);
+    collapsed_macro!(1353);
+    collapsed_macro!(1354);
+    collapsed_macro!(1355);
+    collapsed_macro!(1356);
+    collapsed_macro!(1357);
+    collapsed_macro!(1358);
+    collapsed_macro!(1359);
+    collapsed_macro!(1360);
+    collapsed_macro!(1361);
+    collapsed_macro!(1362);
+    collapsed_macro!(1363);
+    collapsed_macro!(1364);
+    collapsed_macro!(1365);
+    collapsed_macro!(1366);
+    collapsed_macro!(1367);
+    collapsed_macro!(1368);
+    collapsed_macro!(1369);
+    collapsed_macro!(1370);
+    collapsed_macro!(1371);
+    collapsed_macro!(1372);
+    collapsed_macro!(1373);
+    collapsed_macro!(1374);
+    collapsed_macro!(1375);
+    collapsed_macro!(1376);
+    collapsed_macro!(1377);
+    collapsed_macro!(1378);
+    collapsed_macro!(1379);
+    collapsed_macro!(1380);
+    collapsed_macro!(1381);
+    collapsed_macro!(1382);
+    collapsed_macro!(1383);
+    collapsed_macro!(1384);
+    collapsed_macro!(1385);
+    collapsed_macro!(1386);
+    collapsed_macro!(1387);
+    collapsed_macro!(1388);
+    collapsed_macro!(1389);
+    collapsed_macro!(1390);
+    collapsed_macro!(1391);
+    collapsed_macro!(1392);
+    collapsed_macro!(1393);
+    collapsed_macro!(1394);
+    collapsed_macro!(1395);
+    collapsed_macro!(1396);
+    collapsed_macro!(1397);
+    collapsed_macro!(1398);
+    collapsed_macro!(1399);
+    collapsed_macro!(1400);
+    collapsed_macro!(1401);
+    collapsed_macro!(1402);
+    collapsed_macro!(1403);
+    collapsed_macro!(1404);
+    collapsed_macro!(1405);
+    collapsed_macro!(1406);
+    collapsed_macro!(1407);
+    collapsed_macro!(1408);
+    collapsed_macro!(1409);
+    collapsed_macro!(1410);
+    collapsed_macro!(1411);
+    collapsed_macro!(1412);
+    collapsed_macro!(1413);
+    collapsed_macro!(1414);
+    collapsed_macro!(1415);
+    collapsed_macro!(1416);
+    collapsed_macro!(1417);
+    collapsed_macro!(1418);
+    collapsed_macro!(1419);
+    collapsed_macro!(1420);
+    collapsed_macro!(1421);
+    collapsed_macro!(1422);
+    collapsed_macro!(1423);
+    collapsed_macro!(1424);
+    collapsed_macro!(1425);
+    collapsed_macro!(1426);
+    collapsed_macro!(1427);
+    collapsed_macro!(1428);
+    collapsed_macro!(1429);
+    collapsed_macro!(1430);
+    collapsed_macro!(1431);
+    collapsed_macro!(1432);
+    collapsed_macro!(1433);
+    collapsed_macro!(1434);
+    collapsed_macro!(1435);
+    collapsed_macro!(1436);
+    collapsed_macro!(1437);
+    collapsed_macro!(1438);
+    collapsed_macro!(1439);
+    collapsed_macro!(1440);
+    collapsed_macro!(1441);
+    collapsed_macro!(1442);
+    collapsed_macro!(1443);
+    collapsed_macro!(1444);
+    collapsed_macro!(1445);
+    collapsed_macro!(1446);
+    collapsed_macro!(1447);
+    collapsed_macro!(1448);
+    collapsed_macro!(1449);
+    collapsed_macro!(1450);
+    collapsed_macro!(1451);
+    collapsed_macro!(1452);
+    collapsed_macro!(1453);
+    collapsed_macro!(1454);
+    collapsed_macro!(1455);
+    collapsed_macro!(1456);
+    collapsed_macro!(1457);
+    collapsed_macro!(1458);
+    collapsed_macro!(1459);
+    collapsed_macro!(1460);
+    collapsed_macro!(1461);
+    collapsed_macro!(1462);
+    collapsed_macro!(1463);
+    collapsed_macro!(1464);
+    collapsed_macro!(1465);
+    collapsed_macro!(1466);
+    collapsed_macro!(1467);
+    collapsed_macro!(1468);
+    collapsed_macro!(1469);
+    collapsed_macro!(1470);
+    collapsed_macro!(1471);
+    collapsed_macro!(1472);
+    collapsed_macro!(1473);
+    collapsed_macro!(1474);
+    collapsed_macro!(1475);
+    collapsed_macro!(1476);
+    collapsed_macro!(1477);
+    collapsed_macro!(1478);
+    collapsed_macro!(1479);
+    collapsed_macro!(1480);
+    collapsed_macro!(1481);
+    collapsed_macro!(1482);
+    collapsed_macro!(1483);
+    collapsed_macro!(1484);
+    collapsed_macro!(1485);
+    collapsed_macro!(1486);
+    collapsed_macro!(1487);
+    collapsed_macro!(1488);
+    collapsed_macro!(1489);
+    collapsed_macro!(1490);
+    collapsed_macro!(1491);
+    collapsed_macro!(1492);
+    collapsed_macro!(1493);
+    collapsed_macro!(1494);
+    collapsed_macro!(1495);
+    collapsed_macro!(1496);
+    collapsed_macro!(1497);
+    collapsed_macro!(1498);
+    collapsed_macro!(1499);
+    collapsed_macro!(1500);
+    collapsed_macro!(1501);
+    collapsed_macro!(1502);
+    collapsed_macro!(1503);
+    collapsed_macro!(1504);
+    collapsed_macro!(1505);
+    collapsed_macro!(1506);
+    collapsed_macro!(1507);
+    collapsed_macro!(1508);
+    collapsed_macro!(1509);
+    collapsed_macro!(1510);
+    collapsed_macro!(1511);
+    collapsed_macro!(1512);
+    collapsed_macro!(1513);
+    collapsed_macro!(1514);
+    collapsed_macro!(1515);
+    collapsed_macro!(1516);
+    collapsed_macro!(1517);
+    collapsed_macro!(1518);
+    collapsed_macro!(1519);
+    collapsed_macro!(1520);
+    collapsed_macro!(1521);
+    collapsed_macro!(1522);
+    collapsed_macro!(1523);
+    collapsed_macro!(1524);
+    collapsed_macro!(1525);
+    collapsed_macro!(1526);
+    collapsed_macro!(1527);
+    collapsed_macro!(1528);
+    collapsed_macro!(1529);
+    collapsed_macro!(1530);
+    collapsed_macro!(1531);
+    collapsed_macro!(1532);
+    collapsed_macro!(1533);
+    collapsed_macro!(1534);
+    collapsed_macro!(1535);
+    collapsed_macro!(1536);
+    collapsed_macro!(1537);
+    collapsed_macro!(1538);
+    collapsed_macro!(1539);
+    collapsed_macro!(1540);
+    collapsed_macro!(1541);
+    collapsed_macro!(1542);
+    collapsed_macro!(1543);
+    collapsed_macro!(1544);
+    collapsed_macro!(1545);
+    collapsed_macro!(1546);
+    collapsed_macro!(1547);
+    collapsed_macro!(1548);
+    collapsed_macro!(1549);
+    collapsed_macro!(1550);
+    collapsed_macro!(1551);
+    collapsed_macro!(1552);
+    collapsed_macro!(1553);
+    collapsed_macro!(1554);
+    collapsed_macro!(1555);
+    collapsed_macro!(1556);
+    collapsed_macro!(1557);
+    collapsed_macro!(1558);
+    collapsed_macro!(1559);
+    collapsed_macro!(1560);
+    collapsed_macro!(1561);
+    collapsed_macro!(1562);
+    collapsed_macro!(1563);
+    collapsed_macro!(1564);
+    collapsed_macro!(1565);
+    collapsed_macro!(1566);
+    collapsed_macro!(1567);
+    collapsed_macro!(1568);
+    collapsed_macro!(1569);
+    collapsed_macro!(1570);
+    collapsed_macro!(1571);
+    collapsed_macro!(1572);
+    collapsed_macro!(1573);
+    collapsed_macro!(1574);
+    collapsed_macro!(1575);
+    collapsed_macro!(1576);
+    collapsed_macro!(1577);
+    collapsed_macro!(1578);
+    collapsed_macro!(1579);
+    collapsed_macro!(1580);
+    collapsed_macro!(1581);
+    collapsed_macro!(1582);
+    collapsed_macro!(1583);
+    collapsed_macro!(1584);
+    collapsed_macro!(1585);
+    collapsed_macro!(1586);
+    collapsed_macro!(1587);
+    collapsed_macro!(1588);
+    collapsed_macro!(1589);
+    collapsed_macro!(1590);
+    collapsed_macro!(1591);
+    collapsed_macro!(1592);
+    collapsed_macro!(1593);
+    collapsed_macro!(1594);
+    collapsed_macro!(1595);
+    collapsed_macro!(1596);
+    collapsed_macro!(1597);
+    collapsed_macro!(1598);
+    collapsed_macro!(1599);
+    collapsed_macro!(1600);
+    collapsed_macro!(1601);
+    collapsed_macro!(1602);
+    collapsed_macro!(1603);
+    collapsed_macro!(1604);
+    collapsed_macro!(1605);
+    collapsed_macro!(1606);
+    collapsed_macro!(1607);
+    collapsed_macro!(1608);
+    collapsed_macro!(1609);
+    collapsed_macro!(1610);
+    collapsed_macro!(1611);
+    collapsed_macro!(1612);
+    collapsed_macro!(1613);
+    collapsed_macro!(1614);
+    collapsed_macro!(1615);
+    collapsed_macro!(1616);
+    collapsed_macro!(1617);
+    collapsed_macro!(1618);
+    collapsed_macro!(1619);
+    collapsed_macro!(1620);
+    collapsed_macro!(1621);
+    collapsed_macro!(1622);
+    collapsed_macro!(1623);
+    collapsed_macro!(1624);
+    collapsed_macro!(1625);
+    collapsed_macro!(1626);
+    collapsed_macro!(1627);
+    collapsed_macro!(1628);
+    collapsed_macro!(1629);
+    collapsed_macro!(1630);
+    collapsed_macro!(1631);
+    collapsed_macro!(1632);
+    collapsed_macro!(1633);
+    collapsed_macro!(1634);
+    collapsed_macro!(1635);
+    collapsed_macro!(1636);
+    collapsed_macro!(1637);
+    collapsed_macro!(1638);
+    collapsed_macro!(1639);
+    collapsed_macro!(1640);
+    collapsed_macro!(1641);
+    collapsed_macro!(1642);
+    collapsed_macro!(1643);
+    collapsed_macro!(1644);
+    collapsed_macro!(1645);
+    collapsed_macro!(1646);
+    collapsed_macro!(1647);
+    collapsed_macro!(1648);
+    collapsed_macro!(1649);
+    collapsed_macro!(1650);
+    collapsed_macro!(1651);
+    collapsed_macro!(1652);
+    collapsed_macro!(1653);
+    collapsed_macro!(1654);
+    collapsed_macro!(1655);
+    collapsed_macro!(1656);
+    collapsed_macro!(1657);
+    collapsed_macro!(1658);
+    collapsed_macro!(1659);
+    collapsed_macro!(1660);
+    collapsed_macro!(1661);
+    collapsed_macro!(1662);
+    collapsed_macro!(1663);
+    collapsed_macro!(1664);
+    collapsed_macro!(1665);
+    collapsed_macro!(1666);
+    collapsed_macro!(1667);
+    collapsed_macro!(1668);
+    collapsed_macro!(1669);
+    collapsed_macro!(1670);
+    collapsed_macro!(1671);
+    collapsed_macro!(1672);
+    collapsed_macro!(1673);
+    collapsed_macro!(1674);
+    collapsed_macro!(1675);
+    collapsed_macro!(1676);
+    collapsed_macro!(1677);
+    collapsed_macro!(1678);
+    collapsed_macro!(1679);
+    collapsed_macro!(1680);
+    collapsed_macro!(1681);
+    collapsed_macro!(1682);
+    collapsed_macro!(1683);
+    collapsed_macro!(1684);
+    collapsed_macro!(1685);
+    collapsed_macro!(1686);
+    collapsed_macro!(1687);
+    collapsed_macro!(1688);
+    collapsed_macro!(1689);
+    collapsed_macro!(1690);
+    collapsed_macro!(1691);
+    collapsed_macro!(1692);
+    collapsed_macro!(1693);
+    collapsed_macro!(1694);
+    collapsed_macro!(1695);
+    collapsed_macro!(1696);
+    collapsed_macro!(1697);
+    collapsed_macro!(1698);
+    collapsed_macro!(1699);
+    collapsed_macro!(1700);
+    collapsed_macro!(1701);
+    collapsed_macro!(1702);
+    collapsed_macro!(1703);
+    collapsed_macro!(1704);
+    collapsed_macro!(1705);
+    collapsed_macro!(1706);
+    collapsed_macro!(1707);
+    collapsed_macro!(1708);
+    collapsed_macro!(1709);
+    collapsed_macro!(1710);
+    collapsed_macro!(1711);
+    collapsed_macro!(1712);
+    collapsed_macro!(1713);
+    collapsed_macro!(1714);
+    collapsed_macro!(1715);
+    collapsed_macro!(1716);
+    collapsed_macro!(1717);
+    collapsed_macro!(1718);
+    collapsed_macro!(1719);
+    collapsed_macro!(1720);
+    collapsed_macro!(1721);
+    collapsed_macro!(1722);
+    collapsed_macro!(1723);
+    collapsed_macro!(1724);
+    collapsed_macro!(1725);
+    collapsed_macro!(1726);
+    collapsed_macro!(1727);
+    collapsed_macro!(1728);
+    collapsed_macro!(1729);
+    collapsed_macro!(1730);
+    collapsed_macro!(1731);
+    collapsed_macro!(1732);
+    collapsed_macro!(1733);
+    collapsed_macro!(1734);
+    collapsed_macro!(1735);
+    collapsed_macro!(1736);
+    collapsed_macro!(1737);
+    collapsed_macro!(1738);
+    collapsed_macro!(1739);
+    collapsed_macro!(1740);
+    collapsed_macro!(1741);
+    collapsed_macro!(1742);
+    collapsed_macro!(1743);
+    collapsed_macro!(1744);
+    collapsed_macro!(1745);
+    collapsed_macro!(1746);
+    collapsed_macro!(1747);
+    collapsed_macro!(1748);
+    collapsed_macro!(1749);
+    collapsed_macro!(1750);
+    collapsed_macro!(1751);
+    collapsed_macro!(1752);
+    collapsed_macro!(1753);
+    collapsed_macro!(1754);
+    collapsed_macro!(1755);
+    collapsed_macro!(1756);
+    collapsed_macro!(1757);
+    collapsed_macro!(1758);
+    collapsed_macro!(1759);
+    collapsed_macro!(1760);
+    collapsed_macro!(1761);
+    collapsed_macro!(1762);
+    collapsed_macro!(1763);
+    collapsed_macro!(1764);
+    collapsed_macro!(1765);
+    collapsed_macro!(1766);
+    collapsed_macro!(1767);
+    collapsed_macro!(1768);
+    collapsed_macro!(1769);
+    collapsed_macro!(1770);
+    collapsed_macro!(1771);
+    collapsed_macro!(1772);
+    collapsed_macro!(1773);
+    collapsed_macro!(1774);
+    collapsed_macro!(1775);
+    collapsed_macro!(1776);
+    collapsed_macro!(1777);
+    collapsed_macro!(1778);
+    collapsed_macro!(1779);
+    collapsed_macro!(1780);
+    collapsed_macro!(1781);
+    collapsed_macro!(1782);
+    collapsed_macro!(1783);
+    collapsed_macro!(1784);
+    collapsed_macro!(1785);
+    collapsed_macro!(1786);
+    collapsed_macro!(1787);
+    collapsed_macro!(1788);
+    collapsed_macro!(1789);
+    collapsed_macro!(1790);
+    collapsed_macro!(1791);
+    collapsed_macro!(1792);
+    collapsed_macro!(1793);
+    collapsed_macro!(1794);
+    collapsed_macro!(1795);
+    collapsed_macro!(1796);
+    collapsed_macro!(1797);
+    collapsed_macro!(1798);
+    collapsed_macro!(1799);
+    collapsed_macro!(1800);
+    collapsed_macro!(1801);
+    collapsed_macro!(1802);
+    collapsed_macro!(1803);
+    collapsed_macro!(1804);
+    collapsed_macro!(1805);
+    collapsed_macro!(1806);
+    collapsed_macro!(1807);
+    collapsed_macro!(1808);
+    collapsed_macro!(1809);
+    collapsed_macro!(1810);
+    collapsed_macro!(1811);
+    collapsed_macro!(1812);
+    collapsed_macro!(1813);
+    collapsed_macro!(1814);
+    collapsed_macro!(1815);
+    collapsed_macro!(1816);
+    collapsed_macro!(1817);
+    collapsed_macro!(1818);
+    collapsed_macro!(1819);
+    collapsed_macro!(1820);
+    collapsed_macro!(1821);
+    collapsed_macro!(1822);
+    collapsed_macro!(1823);
+    collapsed_macro!(1824);
+    collapsed_macro!(1825);
+    collapsed_macro!(1826);
+    collapsed_macro!(1827);
+    collapsed_macro!(1828);
+    collapsed_macro!(1829);
+    collapsed_macro!(1830);
+    collapsed_macro!(1831);
+    collapsed_macro!(1832);
+    collapsed_macro!(1833);
+    collapsed_macro!(1834);
+    collapsed_macro!(1835);
+    collapsed_macro!(1836);
+    collapsed_macro!(1837);
+    collapsed_macro!(1838);
+    collapsed_macro!(1839);
+    collapsed_macro!(1840);
+    collapsed_macro!(1841);
+    collapsed_macro!(1842);
+    collapsed_macro!(1843);
+    collapsed_macro!(1844);
+    collapsed_macro!(1845);
+    collapsed_macro!(1846);
+    collapsed_macro!(1847);
+    collapsed_macro!(1848);
+    collapsed_macro!(1849);
+    collapsed_macro!(1850);
+    collapsed_macro!(1851);
+    collapsed_macro!(1852);
+    collapsed_macro!(1853);
+    collapsed_macro!(1854);
+    collapsed_macro!(1855);
+    collapsed_macro!(1856);
+    collapsed_macro!(1857);
+    collapsed_macro!(1858);
+    collapsed_macro!(1859);
+    collapsed_macro!(1860);
+    collapsed_macro!(1861);
+    collapsed_macro!(1862);
+    collapsed_macro!(1863);
+    collapsed_macro!(1864);
+    collapsed_macro!(1865);
+    collapsed_macro!(1866);
+    collapsed_macro!(1867);
+    collapsed_macro!(1868);
+    collapsed_macro!(1869);
+    collapsed_macro!(1870);
+    collapsed_macro!(1871);
+    collapsed_macro!(1872);
+    collapsed_macro!(1873);
+    collapsed_macro!(1874);
+    collapsed_macro!(1875);
+    collapsed_macro!(1876);
+    collapsed_macro!(1877);
+    collapsed_macro!(1878);
+    collapsed_macro!(1879);
+    collapsed_macro!(1880);
+    collapsed_macro!(1881);
+    collapsed_macro!(1882);
+    collapsed_macro!(1883);
+    collapsed_macro!(1884);
+    collapsed_macro!(1885);
+    collapsed_macro!(1886);
+    collapsed_macro!(1887);
+    collapsed_macro!(1888);
+    collapsed_macro!(1889);
+    collapsed_macro!(1890);
+    collapsed_macro!(1891);
+    collapsed_macro!(1892);
+    collapsed_macro!(1893);
+    collapsed_macro!(1894);
+    collapsed_macro!(1895);
+    collapsed_macro!(1896);
+    collapsed_macro!(1897);
+    collapsed_macro!(1898);
+    collapsed_macro!(1899);
+    collapsed_macro!(1900);
+    collapsed_macro!(1901);
+    collapsed_macro!(1902);
+    collapsed_macro!(1903);
+    collapsed_macro!(1904);
+    collapsed_macro!(1905);
+    collapsed_macro!(1906);
+    collapsed_macro!(1907);
+    collapsed_macro!(1908);
+    collapsed_macro!(1909);
+    collapsed_macro!(1910);
+    collapsed_macro!(1911);
+    collapsed_macro!(1912);
+    collapsed_macro!(1913);
+    collapsed_macro!(1914);
+    collapsed_macro!(1915);
+    collapsed_macro!(1916);
+    collapsed_macro!(1917);
+    collapsed_macro!(1918);
+    collapsed_macro!(1919);
+    collapsed_macro!(1920);
+    collapsed_macro!(1921);
+    collapsed_macro!(1922);
+    collapsed_macro!(1923);
+    collapsed_macro!(1924);
+    collapsed_macro!(1925);
+    collapsed_macro!(1926);
+    collapsed_macro!(1927);
+    collapsed_macro!(1928);
+    collapsed_macro!(1929);
+    collapsed_macro!(1930);
+    collapsed_macro!(1931);
+    collapsed_macro!(1932);
+    collapsed_macro!(1933);
+    collapsed_macro!(1934);
+    collapsed_macro!(1935);
+    collapsed_macro!(1936);
+    collapsed_macro!(1937);
+    collapsed_macro!(1938);
+    collapsed_macro!(1939);
+    collapsed_macro!(1940);
+    collapsed_macro!(1941);
+    collapsed_macro!(1942);
+    collapsed_macro!(1943);
+    collapsed_macro!(1944);
+    collapsed_macro!(1945);
+    collapsed_macro!(1946);
+    collapsed_macro!(1947);
+    collapsed_macro!(1948);
+    collapsed_macro!(1949);
+    collapsed_macro!(1950);
+    collapsed_macro!(1951);
+    collapsed_macro!(1952);
+    collapsed_macro!(1953);
+    collapsed_macro!(1954);
+    collapsed_macro!(1955);
+    collapsed_macro!(1956);
+    collapsed_macro!(1957);
+    collapsed_macro!(1958);
+    collapsed_macro!(1959);
+    collapsed_macro!(1960);
+    collapsed_macro!(1961);
+    collapsed_macro!(1962);
+    collapsed_macro!(1963);
+    collapsed_macro!(1964);
+    collapsed_macro!(1965);
+    collapsed_macro!(1966);
+    collapsed_macro!(1967);
+    collapsed_macro!(1968);
+    collapsed_macro!(1969);
+    collapsed_macro!(1970);
+    collapsed_macro!(1971);
+    collapsed_macro!(1972);
+    collapsed_macro!(1973);
+    collapsed_macro!(1974);
+    collapsed_macro!(1975);
+    collapsed_macro!(1976);
+    collapsed_macro!(1977);
+    collapsed_macro!(1978);
+    collapsed_macro!(1979);
+    collapsed_macro!(1980);
+    collapsed_macro!(1981);
+    collapsed_macro!(1982);
+    collapsed_macro!(1983);
+    collapsed_macro!(1984);
+    collapsed_macro!(1985);
+    collapsed_macro!(1986);
+    collapsed_macro!(1987);
+    collapsed_macro!(1988);
+    collapsed_macro!(1989);
+    collapsed_macro!(1990);
+    collapsed_macro!(1991);
+    collapsed_macro!(1992);
+    collapsed_macro!(1993);
+    collapsed_macro!(1994);
+    collapsed_macro!(1995);
+    collapsed_macro!(1996);
+    collapsed_macro!(1997);
+    collapsed_macro!(1998);
+    collapsed_macro!(1999);
+    collapsed_macro!(2000);
+    collapsed_macro!(2001);
+    collapsed_macro!(2002);
+    collapsed_macro!(2003);
+    collapsed_macro!(2004);
+    collapsed_macro!(2005);
+    collapsed_macro!(2006);
+    collapsed_macro!(2007);
+    collapsed_macro!(2008);
+    collapsed_macro!(2009);
+    collapsed_macro!(2010);
+    collapsed_macro!(2011);
+    collapsed_macro!(2012);
+    collapsed_macro!(2013);
+    collapsed_macro!(2014);
+    collapsed_macro!(2015);
+    collapsed_macro!(2016);
+    collapsed_macro!(2017);
+    collapsed_macro!(2018);
+    collapsed_macro!(2019);
+    collapsed_macro!(2020);
+    collapsed_macro!(2021);
+    collapsed_macro!(2022);
+    collapsed_macro!(2023);
+    collapsed_macro!(2024);
+    collapsed_macro!(2025);
+    collapsed_macro!(2026);
+    collapsed_macro!(2027);
+    collapsed_macro!(2028);
+    collapsed_macro!(2029);
+    collapsed_macro!(2030);
+    collapsed_macro!(2031);
+    collapsed_macro!(2032);
+    collapsed_macro!(2033);
+    collapsed_macro!(2034);
+    collapsed_macro!(2035);
+    collapsed_macro!(2036);
+    collapsed_macro!(2037);
+    collapsed_macro!(2038);
+    collapsed_macro!(2039);
+    collapsed_macro!(2040);
+    collapsed_macro!(2041);
+    collapsed_macro!(2042);
+    collapsed_macro!(2043);
+    collapsed_macro!(2044);
+    collapsed_macro!(2045);
+    collapsed_macro!(2046);
+    collapsed_macro!(2047);
+    collapsed_macro!(2048);
+    collapsed_macro!(2049);
+    collapsed_macro!(2050);
+    collapsed_macro!(2051);
+    collapsed_macro!(2052);
+    collapsed_macro!(2053);
+    collapsed_macro!(2054);
+    collapsed_macro!(2055);
+    collapsed_macro!(2056);
+    collapsed_macro!(2057);
+    collapsed_macro!(2058);
+    collapsed_macro!(2059);
+    collapsed_macro!(2060);
+    collapsed_macro!(2061);
+    collapsed_macro!(2062);
+    collapsed_macro!(2063);
+    collapsed_macro!(2064);
+    collapsed_macro!(2065);
+    collapsed_macro!(2066);
+    collapsed_macro!(2067);
+    collapsed_macro!(2068);
+    collapsed_macro!(2069);
+    collapsed_macro!(2070);
+    collapsed_macro!(2071);
+    collapsed_macro!(2072);
+    collapsed_macro!(2073);
+    collapsed_macro!(2074);
+    collapsed_macro!(2075);
+    collapsed_macro!(2076);
+    collapsed_macro!(2077);
+    collapsed_macro!(2078);
+    collapsed_macro!(2079);
+    collapsed_macro!(2080);
+    collapsed_macro!(2081);
+    collapsed_macro!(2082);
+    collapsed_macro!(2083);
+    collapsed_macro!(2084);
+    collapsed_macro!(2085);
+    collapsed_macro!(2086);
+    collapsed_macro!(2087);
+    collapsed_macro!(2088);
+    collapsed_macro!(2089);
+    collapsed_macro!(2090);
+    collapsed_macro!(2091);
+    collapsed_macro!(2092);
+    collapsed_macro!(2093);
+    collapsed_macro!(2094);
+    collapsed_macro!(2095);
+    collapsed_macro!(2096);
+    collapsed_macro!(2097);
+    collapsed_macro!(2098);
+    collapsed_macro!(2099);
+    collapsed_macro!(2100);
+    collapsed_macro!(2101);
+    collapsed_macro!(2102);
+    collapsed_macro!(2103);
+    collapsed_macro!(2104);
+    collapsed_macro!(2105);
+    collapsed_macro!(2106);
+    collapsed_macro!(2107);
+    collapsed_macro!(2108);
+    collapsed_macro!(2109);
+    collapsed_macro!(2110);
+    collapsed_macro!(2111);
+    collapsed_macro!(2112);
+    collapsed_macro!(2113);
+    collapsed_macro!(2114);
+    collapsed_macro!(2115);
+    collapsed_macro!(2116);
+    collapsed_macro!(2117);
+    collapsed_macro!(2118);
+    collapsed_macro!(2119);
+    collapsed_macro!(2120);
+    collapsed_macro!(2121);
+    collapsed_macro!(2122);
+    collapsed_macro!(2123);
+    collapsed_macro!(2124);
+    collapsed_macro!(2125);
+    collapsed_macro!(2126);
+    collapsed_macro!(2127);
+    collapsed_macro!(2128);
+    collapsed_macro!(2129);
+    collapsed_macro!(2130);
+    collapsed_macro!(2131);
+    collapsed_macro!(2132);
+    collapsed_macro!(2133);
+    collapsed_macro!(2134);
+    collapsed_macro!(2135);
+    collapsed_macro!(2136);
+    collapsed_macro!(2137);
+    collapsed_macro!(2138);
+    collapsed_macro!(2139);
+    collapsed_macro!(2140);
+    collapsed_macro!(2141);
+    collapsed_macro!(2142);
+    collapsed_macro!(2143);
+    collapsed_macro!(2144);
+    collapsed_macro!(2145);
+    collapsed_macro!(2146);
+    collapsed_macro!(2147);
+    collapsed_macro!(2148);
+    collapsed_macro!(2149);
+    collapsed_macro!(2150);
+    collapsed_macro!(2151);
+    collapsed_macro!(2152);
+    collapsed_macro!(2153);
+    collapsed_macro!(2154);
+    collapsed_macro!(2155);
+    collapsed_macro!(2156);
+    collapsed_macro!(2157);
+    collapsed_macro!(2158);
+    collapsed_macro!(2159);
+    collapsed_macro!(2160);
+    collapsed_macro!(2161);
+    collapsed_macro!(2162);
+    collapsed_macro!(2163);
+    collapsed_macro!(2164);
+    collapsed_macro!(2165);
+    collapsed_macro!(2166);
+    collapsed_macro!(2167);
+    collapsed_macro!(2168);
+    collapsed_macro!(2169);
+    collapsed_macro!(2170);
+    collapsed_macro!(2171);
+    collapsed_macro!(2172);
+    collapsed_macro!(2173);
+    collapsed_macro!(2174);
+    collapsed_macro!(2175);
+    collapsed_macro!(2176);
+    collapsed_macro!(2177);
+    collapsed_macro!(2178);
+    collapsed_macro!(2179);
+    collapsed_macro!(2180);
+    collapsed_macro!(2181);
+    collapsed_macro!(2182);
+    collapsed_macro!(2183);
+    collapsed_macro!(2184);
+    collapsed_macro!(2185);
+    collapsed_macro!(2186);
+    collapsed_macro!(2187);
+    collapsed_macro!(2188);
+    collapsed_macro!(2189);
+    collapsed_macro!(2190);
+    collapsed_macro!(2191);
+    collapsed_macro!(2192);
+    collapsed_macro!(2193);
+    collapsed_macro!(2194);
+    collapsed_macro!(2195);
+    collapsed_macro!(2196);
+    collapsed_macro!(2197);
+    collapsed_macro!(2198);
+    collapsed_macro!(2199);
+    collapsed_macro!(2200);
+    collapsed_macro!(2201);
+    collapsed_macro!(2202);
+    collapsed_macro!(2203);
+    collapsed_macro!(2204);
+    collapsed_macro!(2205);
+    collapsed_macro!(2206);
+    collapsed_macro!(2207);
+    collapsed_macro!(2208);
+    collapsed_macro!(2209);
+    collapsed_macro!(2210);
+    collapsed_macro!(2211);
+    collapsed_macro!(2212);
+    collapsed_macro!(2213);
+    collapsed_macro!(2214);
+    collapsed_macro!(2215);
+    collapsed_macro!(2216);
+    collapsed_macro!(2217);
+    collapsed_macro!(2218);
+    collapsed_macro!(2219);
+    collapsed_macro!(2220);
+    collapsed_macro!(2221);
+    collapsed_macro!(2222);
+    collapsed_macro!(2223);
+    collapsed_macro!(2224);
+    collapsed_macro!(2225);
+    collapsed_macro!(2226);
+    collapsed_macro!(2227);
+    collapsed_macro!(2228);
+    collapsed_macro!(2229);
+    collapsed_macro!(2230);
+    collapsed_macro!(2231);
+    collapsed_macro!(2232);
+    collapsed_macro!(2233);
+    collapsed_macro!(2234);
+    collapsed_macro!(2235);
+    collapsed_macro!(2236);
+    collapsed_macro!(2237);
+    collapsed_macro!(2238);
+    collapsed_macro!(2239);
+    collapsed_macro!(2240);
+    collapsed_macro!(2241);
+    collapsed_macro!(2242);
+    collapsed_macro!(2243);
+    collapsed_macro!(2244);
+    collapsed_macro!(2245);
+    collapsed_macro!(2246);
+    collapsed_macro!(2247);
+    collapsed_macro!(2248);
+    collapsed_macro!(2249);
+    collapsed_macro!(2250);
+    collapsed_macro!(2251);
+    collapsed_macro!(2252);
+    collapsed_macro!(2253);
+    collapsed_macro!(2254);
+    collapsed_macro!(2255);
+    collapsed_macro!(2256);
+    collapsed_macro!(2257);
+    collapsed_macro!(2258);
+    collapsed_macro!(2259);
+    collapsed_macro!(2260);
+    collapsed_macro!(2261);
+    collapsed_macro!(2262);
+    collapsed_macro!(2263);
+    collapsed_macro!(2264);
+    collapsed_macro!(2265);
+    collapsed_macro!(2266);
+    collapsed_macro!(2267);
+    collapsed_macro!(2268);
+    collapsed_macro!(2269);
+    collapsed_macro!(2270);
+    collapsed_macro!(2271);
+    collapsed_macro!(2272);
+    collapsed_macro!(2273);
+    collapsed_macro!(2274);
+    collapsed_macro!(2275);
+    collapsed_macro!(2276);
+    collapsed_macro!(2277);
+    collapsed_macro!(2278);
+    collapsed_macro!(2279);
+    collapsed_macro!(2280);
+    collapsed_macro!(2281);
+    collapsed_macro!(2282);
+    collapsed_macro!(2283);
+    collapsed_macro!(2284);
+    collapsed_macro!(2285);
+    collapsed_macro!(2286);
+    collapsed_macro!(2287);
+    collapsed_macro!(2288);
+    collapsed_macro!(2289);
+    collapsed_macro!(2290);
+    collapsed_macro!(2291);
+    collapsed_macro!(2292);
+    collapsed_macro!(2293);
+    collapsed_macro!(2294);
+    collapsed_macro!(2295);
+    collapsed_macro!(2296);
+    collapsed_macro!(2297);
+    collapsed_macro!(2298);
+    collapsed_macro!(2299);
+    collapsed_macro!(2300);
+    collapsed_macro!(2301);
+    collapsed_macro!(2302);
+    collapsed_macro!(2303);
+    collapsed_macro!(2304);
+    collapsed_macro!(2305);
+    collapsed_macro!(2306);
+    collapsed_macro!(2307);
+    collapsed_macro!(2308);
+    collapsed_macro!(2309);
+    collapsed_macro!(2310);
+    collapsed_macro!(2311);
+    collapsed_macro!(2312);
+    collapsed_macro!(2313);
+    collapsed_macro!(2314);
+    collapsed_macro!(2315);
+    collapsed_macro!(2316);
+    collapsed_macro!(2317);
+    collapsed_macro!(2318);
+    collapsed_macro!(2319);
+    collapsed_macro!(2320);
+    collapsed_macro!(2321);
+    collapsed_macro!(2322);
+    collapsed_macro!(2323);
+    collapsed_macro!(2324);
+    collapsed_macro!(2325);
+    collapsed_macro!(2326);
+    collapsed_macro!(2327);
+    collapsed_macro!(2328);
+    collapsed_macro!(2329);
+    collapsed_macro!(2330);
+    collapsed_macro!(2331);
+    collapsed_macro!(2332);
+    collapsed_macro!(2333);
+    collapsed_macro!(2334);
+    collapsed_macro!(2335);
+    collapsed_macro!(2336);
+    collapsed_macro!(2337);
+    collapsed_macro!(2338);
+    collapsed_macro!(2339);
+    collapsed_macro!(2340);
+    collapsed_macro!(2341);
+    collapsed_macro!(2342);
+    collapsed_macro!(2343);
+    collapsed_macro!(2344);
+    collapsed_macro!(2345);
+    collapsed_macro!(2346);
+    collapsed_macro!(2347);
+    collapsed_macro!(2348);
+    collapsed_macro!(2349);
+    collapsed_macro!(2350);
+    collapsed_macro!(2351);
+    collapsed_macro!(2352);
+    collapsed_macro!(2353);
+    collapsed_macro!(2354);
+    collapsed_macro!(2355);
+    collapsed_macro!(2356);
+    collapsed_macro!(2357);
+    collapsed_macro!(2358);
+    collapsed_macro!(2359);
+    collapsed_macro!(2360);
+    collapsed_macro!(2361);
+    collapsed_macro!(2362);
+    collapsed_macro!(2363);
+    collapsed_macro!(2364);
+    collapsed_macro!(2365);
+    collapsed_macro!(2366);
+    collapsed_macro!(2367);
+    collapsed_macro!(2368);
+    collapsed_macro!(2369);
+    collapsed_macro!(2370);
+    collapsed_macro!(2371);
+    collapsed_macro!(2372);
+    collapsed_macro!(2373);
+    collapsed_macro!(2374);
+    collapsed_macro!(2375);
+    collapsed_macro!(2376);
+    collapsed_macro!(2377);
+    collapsed_macro!(2378);
+    collapsed_macro!(2379);
+    collapsed_macro!(2380);
+    collapsed_macro!(2381);
+    collapsed_macro!(2382);
+    collapsed_macro!(2383);
+    collapsed_macro!(2384);
+    collapsed_macro!(2385);
+    collapsed_macro!(2386);
+    collapsed_macro!(2387);
+    collapsed_macro!(2388);
+    collapsed_macro!(2389);
+    collapsed_macro!(2390);
+    collapsed_macro!(2391);
+    collapsed_macro!(2392);
+    collapsed_macro!(2393);
+    collapsed_macro!(2394);
+    collapsed_macro!(2395);
+    collapsed_macro!(2396);
+    collapsed_macro!(2397);
+    collapsed_macro!(2398);
+    collapsed_macro!(2399);
+    collapsed_macro!(2400);
+    collapsed_macro!(2401);
+    collapsed_macro!(2402);
+    collapsed_macro!(2403);
+    collapsed_macro!(2404);
+    collapsed_macro!(2405);
+    collapsed_macro!(2406);
+    collapsed_macro!(2407);
+    collapsed_macro!(2408);
+    collapsed_macro!(2409);
+    collapsed_macro!(2410);
+    collapsed_macro!(2411);
+    collapsed_macro!(2412);
+    collapsed_macro!(2413);
+    collapsed_macro!(2414);
+    collapsed_macro!(2415);
+    collapsed_macro!(2416);
+    collapsed_macro!(2417);
+    collapsed_macro!(2418);
+    collapsed_macro!(2419);
+    collapsed_macro!(2420);
+    collapsed_macro!(2421);
+    collapsed_macro!(2422);
+    collapsed_macro!(2423);
+    collapsed_macro!(2424);
+    collapsed_macro!(2425);
+    collapsed_macro!(2426);
+    collapsed_macro!(2427);
+    collapsed_macro!(2428);
+    collapsed_macro!(2429);
+    collapsed_macro!(2430);
+    collapsed_macro!(2431);
+    collapsed_macro!(2432);
+    collapsed_macro!(2433);
+    collapsed_macro!(2434);
+    collapsed_macro!(2435);
+    collapsed_macro!(2436);
+    collapsed_macro!(2437);
+    collapsed_macro!(2438);
+    collapsed_macro!(2439);
+    collapsed_macro!(2440);
+    collapsed_macro!(2441);
+    collapsed_macro!(2442);
+    collapsed_macro!(2443);
+    collapsed_macro!(2444);
+    collapsed_macro!(2445);
+    collapsed_macro!(2446);
+    collapsed_macro!(2447);
+    collapsed_macro!(2448);
+    collapsed_macro!(2449);
+    collapsed_macro!(2450);
+    collapsed_macro!(2451);
+    collapsed_macro!(2452);
+    collapsed_macro!(2453);
+    collapsed_macro!(2454);
+    collapsed_macro!(2455);
+    collapsed_macro!(2456);
+    collapsed_macro!(2457);
+    collapsed_macro!(2458);
+    collapsed_macro!(2459);
+    collapsed_macro!(2460);
+    collapsed_macro!(2461);
+    collapsed_macro!(2462);
+    collapsed_macro!(2463);
+    collapsed_macro!(2464);
+    collapsed_macro!(2465);
+    collapsed_macro!(2466);
+    collapsed_macro!(2467);
+    collapsed_macro!(2468);
+    collapsed_macro!(2469);
+    collapsed_macro!(2470);
+    collapsed_macro!(2471);
+    collapsed_macro!(2472);
+    collapsed_macro!(2473);
+    collapsed_macro!(2474);
+    collapsed_macro!(2475);
+    collapsed_macro!(2476);
+    collapsed_macro!(2477);
+    collapsed_macro!(2478);
+    collapsed_macro!(2479);
+    collapsed_macro!(2480);
+    collapsed_macro!(2481);
+    collapsed_macro!(2482);
+    collapsed_macro!(2483);
+    collapsed_macro!(2484);
+    collapsed_macro!(2485);
+    collapsed_macro!(2486);
+    collapsed_macro!(2487);
+    collapsed_macro!(2488);
+    collapsed_macro!(2489);
+    collapsed_macro!(2490);
+    collapsed_macro!(2491);
+    collapsed_macro!(2492);
+    collapsed_macro!(2493);
+    collapsed_macro!(2494);
+    collapsed_macro!(2495);
+    collapsed_macro!(2496);
+    collapsed_macro!(2497);
+    collapsed_macro!(2498);
+    collapsed_macro!(2499);
+    collapsed_macro!(2500);
+    collapsed_macro!(2501);
+    collapsed_macro!(2502);
+    collapsed_macro!(2503);
+    collapsed_macro!(2504);
+    collapsed_macro!(2505);
+    collapsed_macro!(2506);
+    collapsed_macro!(2507);
+    collapsed_macro!(2508);
+    collapsed_macro!(2509);
+    collapsed_macro!(2510);
+    collapsed_macro!(2511);
+    collapsed_macro!(2512);
+    collapsed_macro!(2513);
+    collapsed_macro!(2514);
+    collapsed_macro!(2515);
+    collapsed_macro!(2516);
+    collapsed_macro!(2517);
+    collapsed_macro!(2518);
+    collapsed_macro!(2519);
+    collapsed_macro!(2520);
+    collapsed_macro!(2521);
+    collapsed_macro!(2522);
+    collapsed_macro!(2523);
+    collapsed_macro!(2524);
+    collapsed_macro!(2525);
+    collapsed_macro!(2526);
+    collapsed_macro!(2527);
+    collapsed_macro!(2528);
+    collapsed_macro!(2529);
+    collapsed_macro!(2530);
+    collapsed_macro!(2531);
+    collapsed_macro!(2532);
+    collapsed_macro!(2533);
+    collapsed_macro!(2534);
+    collapsed_macro!(2535);
+    collapsed_macro!(2536);
+    collapsed_macro!(2537);
+    collapsed_macro!(2538);
+    collapsed_macro!(2539);
+    collapsed_macro!(2540);
+    collapsed_macro!(2541);
+    collapsed_macro!(2542);
+    collapsed_macro!(2543);
+    collapsed_macro!(2544);
+    collapsed_macro!(2545);
+    collapsed_macro!(2546);
+    collapsed_macro!(2547);
+    collapsed_macro!(2548);
+    collapsed_macro!(2549);
+    collapsed_macro!(2550);
+    collapsed_macro!(2551);
+    collapsed_macro!(2552);
+    collapsed_macro!(2553);
+    collapsed_macro!(2554);
+    collapsed_macro!(2555);
+    collapsed_macro!(2556);
+    collapsed_macro!(2557);
+    collapsed_macro!(2558);
+    collapsed_macro!(2559);
+    collapsed_macro!(2560);
+    collapsed_macro!(2561);
+    collapsed_macro!(2562);
+    collapsed_macro!(2563);
+    collapsed_macro!(2564);
+    collapsed_macro!(2565);
+    collapsed_macro!(2566);
+    collapsed_macro!(2567);
+    collapsed_macro!(2568);
+    collapsed_macro!(2569);
+    collapsed_macro!(2570);
+    collapsed_macro!(2571);
+    collapsed_macro!(2572);
+    collapsed_macro!(2573);
+    collapsed_macro!(2574);
+    collapsed_macro!(2575);
+    collapsed_macro!(2576);
+    collapsed_macro!(2577);
+    collapsed_macro!(2578);
+    collapsed_macro!(2579);
+    collapsed_macro!(2580);
+    collapsed_macro!(2581);
+    collapsed_macro!(2582);
+    collapsed_macro!(2583);
+    collapsed_macro!(2584);
+    collapsed_macro!(2585);
+    collapsed_macro!(2586);
+    collapsed_macro!(2587);
+    collapsed_macro!(2588);
+    collapsed_macro!(2589);
+    collapsed_macro!(2590);
+    collapsed_macro!(2591);
+    collapsed_macro!(2592);
+    collapsed_macro!(2593);
+    collapsed_macro!(2594);
+    collapsed_macro!(2595);
+    collapsed_macro!(2596);
+    collapsed_macro!(2597);
+    collapsed_macro!(2598);
+    collapsed_macro!(2599);
+    collapsed_macro!(2600);
+    collapsed_macro!(2601);
+    collapsed_macro!(2602);
+    collapsed_macro!(2603);
+    collapsed_macro!(2604);
+    collapsed_macro!(2605);
+    collapsed_macro!(2606);
+    collapsed_macro!(2607);
+    collapsed_macro!(2608);
+    collapsed_macro!(2609);
+    collapsed_macro!(2610);
+    collapsed_macro!(2611);
+    collapsed_macro!(2612);
+    collapsed_macro!(2613);
+    collapsed_macro!(2614);
+    collapsed_macro!(2615);
+    collapsed_macro!(2616);
+    collapsed_macro!(2617);
+    collapsed_macro!(2618);
+    collapsed_macro!(2619);
+    collapsed_macro!(2620);
+    collapsed_macro!(2621);
+    collapsed_macro!(2622);
+    collapsed_macro!(2623);
+    collapsed_macro!(2624);
+    collapsed_macro!(2625);
+    collapsed_macro!(2626);
+    collapsed_macro!(2627);
+    collapsed_macro!(2628);
+    collapsed_macro!(2629);
+    collapsed_macro!(2630);
+    collapsed_macro!(2631);
+    collapsed_macro!(2632);
+    collapsed_macro!(2633);
+    collapsed_macro!(2634);
+    collapsed_macro!(2635);
+    collapsed_macro!(2636);
+    collapsed_macro!(2637);
+    collapsed_macro!(2638);
+    collapsed_macro!(2639);
+    collapsed_macro!(2640);
+    collapsed_macro!(2641);
+    collapsed_macro!(2642);
+    collapsed_macro!(2643);
+    collapsed_macro!(2644);
+    collapsed_macro!(2645);
+    collapsed_macro!(2646);
+    collapsed_macro!(2647);
+    collapsed_macro!(2648);
+    collapsed_macro!(2649);
+    collapsed_macro!(2650);
+    collapsed_macro!(2651);
+    collapsed_macro!(2652);
+    collapsed_macro!(2653);
+    collapsed_macro!(2654);
+    collapsed_macro!(2655);
+    collapsed_macro!(2656);
+    collapsed_macro!(2657);
+    collapsed_macro!(2658);
+    collapsed_macro!(2659);
+    collapsed_macro!(2660);
+    collapsed_macro!(2661);
+    collapsed_macro!(2662);
+    collapsed_macro!(2663);
+    collapsed_macro!(2664);
+    collapsed_macro!(2665);
+    collapsed_macro!(2666);
+    collapsed_macro!(2667);
+    collapsed_macro!(2668);
+    collapsed_macro!(2669);
+    collapsed_macro!(2670);
+    collapsed_macro!(2671);
+    collapsed_macro!(2672);
+    collapsed_macro!(2673);
+    collapsed_macro!(2674);
+    collapsed_macro!(2675);
+    collapsed_macro!(2676);
+    collapsed_macro!(2677);
+    collapsed_macro!(2678);
+    collapsed_macro!(2679);
+    collapsed_macro!(2680);
+    collapsed_macro!(2681);
+    collapsed_macro!(2682);
+    collapsed_macro!(2683);
+    collapsed_macro!(2684);
+    collapsed_macro!(2685);
+    collapsed_macro!(2686);
+    collapsed_macro!(2687);
+    collapsed_macro!(2688);
+    collapsed_macro!(2689);
+    collapsed_macro!(2690);
+    collapsed_macro!(2691);
+    collapsed_macro!(2692);
+    collapsed_macro!(2693);
+    collapsed_macro!(2694);
+    collapsed_macro!(2695);
+    collapsed_macro!(2696);
+    collapsed_macro!(2697);
+    collapsed_macro!(2698);
+    collapsed_macro!(2699);
+    collapsed_macro!(2700);
+    collapsed_macro!(2701);
+    collapsed_macro!(2702);
+    collapsed_macro!(2703);
+    collapsed_macro!(2704);
+    collapsed_macro!(2705);
+    collapsed_macro!(2706);
+    collapsed_macro!(2707);
+    collapsed_macro!(2708);
+    collapsed_macro!(2709);
+    collapsed_macro!(2710);
+    collapsed_macro!(2711);
+    collapsed_macro!(2712);
+    collapsed_macro!(2713);
+    collapsed_macro!(2714);
+    collapsed_macro!(2715);
+    collapsed_macro!(2716);
+    collapsed_macro!(2717);
+    collapsed_macro!(2718);
+    collapsed_macro!(2719);
+    collapsed_macro!(2720);
+    collapsed_macro!(2721);
+    collapsed_macro!(2722);
+    collapsed_macro!(2723);
+    collapsed_macro!(2724);
+    collapsed_macro!(2725);
+    collapsed_macro!(2726);
+    collapsed_macro!(2727);
+    collapsed_macro!(2728);
+    collapsed_macro!(2729);
+    collapsed_macro!(2730);
+    collapsed_macro!(2731);
+    collapsed_macro!(2732);
+    collapsed_macro!(2733);
+    collapsed_macro!(2734);
+    collapsed_macro!(2735);
+    collapsed_macro!(2736);
+    collapsed_macro!(2737);
+    collapsed_macro!(2738);
+    collapsed_macro!(2739);
+    collapsed_macro!(2740);
+    collapsed_macro!(2741);
+    collapsed_macro!(2742);
+    collapsed_macro!(2743);
+    collapsed_macro!(2744);
+    collapsed_macro!(2745);
+    collapsed_macro!(2746);
+    collapsed_macro!(2747);
+    collapsed_macro!(2748);
+    collapsed_macro!(2749);
+    collapsed_macro!(2750);
+    collapsed_macro!(2751);
+    collapsed_macro!(2752);
+    collapsed_macro!(2753);
+    collapsed_macro!(2754);
+    collapsed_macro!(2755);
+    collapsed_macro!(2756);
+    collapsed_macro!(2757);
+    collapsed_macro!(2758);
+    collapsed_macro!(2759);
+    collapsed_macro!(2760);
+    collapsed_macro!(2761);
+    collapsed_macro!(2762);
+    collapsed_macro!(2763);
+    collapsed_macro!(2764);
+    collapsed_macro!(2765);
+    collapsed_macro!(2766);
+    collapsed_macro!(2767);
+    collapsed_macro!(2768);
+    collapsed_macro!(2769);
+    collapsed_macro!(2770);
+    collapsed_macro!(2771);
+    collapsed_macro!(2772);
+    collapsed_macro!(2773);
+    collapsed_macro!(2774);
+    collapsed_macro!(2775);
+    collapsed_macro!(2776);
+    collapsed_macro!(2777);
+    collapsed_macro!(2778);
+    collapsed_macro!(2779);
+    collapsed_macro!(2780);
+    collapsed_macro!(2781);
+    collapsed_macro!(2782);
+    collapsed_macro!(2783);
+    collapsed_macro!(2784);
+    collapsed_macro!(2785);
+    collapsed_macro!(2786);
+    collapsed_macro!(2787);
+    collapsed_macro!(2788);
+    collapsed_macro!(2789);
+    collapsed_macro!(2790);
+    collapsed_macro!(2791);
+    collapsed_macro!(2792);
+    collapsed_macro!(2793);
+    collapsed_macro!(2794);
+    collapsed_macro!(2795);
+    collapsed_macro!(2796);
+    collapsed_macro!(2797);
+    collapsed_macro!(2798);
+    collapsed_macro!(2799);
+    collapsed_macro!(2800);
+    collapsed_macro!(2801);
+    collapsed_macro!(2802);
+    collapsed_macro!(2803);
+    collapsed_macro!(2804);
+    collapsed_macro!(2805);
+    collapsed_macro!(2806);
+    collapsed_macro!(2807);
+    collapsed_macro!(2808);
+    collapsed_macro!(2809);
+    collapsed_macro!(2810);
+    collapsed_macro!(2811);
+    collapsed_macro!(2812);
+    collapsed_macro!(2813);
+    collapsed_macro!(2814);
+    collapsed_macro!(2815);
+    collapsed_macro!(2816);
+    collapsed_macro!(2817);
+    collapsed_macro!(2818);
+    collapsed_macro!(2819);
+    collapsed_macro!(2820);
+    collapsed_macro!(2821);
+    collapsed_macro!(2822);
+    collapsed_macro!(2823);
+    collapsed_macro!(2824);
+    collapsed_macro!(2825);
+    collapsed_macro!(2826);
+    collapsed_macro!(2827);
+    collapsed_macro!(2828);
+    collapsed_macro!(2829);
+    collapsed_macro!(2830);
+    collapsed_macro!(2831);
+    collapsed_macro!(2832);
+    collapsed_macro!(2833);
+    collapsed_macro!(2834);
+    collapsed_macro!(2835);
+    collapsed_macro!(2836);
+    collapsed_macro!(2837);
+    collapsed_macro!(2838);
+    collapsed_macro!(2839);
+    collapsed_macro!(2840);
+    collapsed_macro!(2841);
+    collapsed_macro!(2842);
+    collapsed_macro!(2843);
+    collapsed_macro!(2844);
+    collapsed_macro!(2845);
+    collapsed_macro!(2846);
+    collapsed_macro!(2847);
+    collapsed_macro!(2848);
+    collapsed_macro!(2849);
+    collapsed_macro!(2850);
+    collapsed_macro!(2851);
+    collapsed_macro!(2852);
+    collapsed_macro!(2853);
+    collapsed_macro!(2854);
+    collapsed_macro!(2855);
+    collapsed_macro!(2856);
+    collapsed_macro!(2857);
+    collapsed_macro!(2858);
+    collapsed_macro!(2859);
+    collapsed_macro!(2860);
+    collapsed_macro!(2861);
+    collapsed_macro!(2862);
+    collapsed_macro!(2863);
+    collapsed_macro!(2864);
+    collapsed_macro!(2865);
+    collapsed_macro!(2866);
+    collapsed_macro!(2867);
+    collapsed_macro!(2868);
+    collapsed_macro!(2869);
+    collapsed_macro!(2870);
+    collapsed_macro!(2871);
+    collapsed_macro!(2872);
+    collapsed_macro!(2873);
+    collapsed_macro!(2874);
+    collapsed_macro!(2875);
+    collapsed_macro!(2876);
+    collapsed_macro!(2877);
+    collapsed_macro!(2878);
+    collapsed_macro!(2879);
+    collapsed_macro!(2880);
+    collapsed_macro!(2881);
+    collapsed_macro!(2882);
+    collapsed_macro!(2883);
+    collapsed_macro!(2884);
+    collapsed_macro!(2885);
+    collapsed_macro!(2886);
+    collapsed_macro!(2887);
+    collapsed_macro!(2888);
+    collapsed_macro!(2889);
+    collapsed_macro!(2890);
+    collapsed_macro!(2891);
+    collapsed_macro!(2892);
+    collapsed_macro!(2893);
+    collapsed_macro!(2894);
+    collapsed_macro!(2895);
+    collapsed_macro!(2896);
+    collapsed_macro!(2897);
+    collapsed_macro!(2898);
+    collapsed_macro!(2899);
+    collapsed_macro!(2900);
+    collapsed_macro!(2901);
+    collapsed_macro!(2902);
+    collapsed_macro!(2903);
+    collapsed_macro!(2904);
+    collapsed_macro!(2905);
+    collapsed_macro!(2906);
+    collapsed_macro!(2907);
+    collapsed_macro!(2908);
+    collapsed_macro!(2909);
+    collapsed_macro!(2910);
+    collapsed_macro!(2911);
+    collapsed_macro!(2912);
+    collapsed_macro!(2913);
+    collapsed_macro!(2914);
+    collapsed_macro!(2915);
+    collapsed_macro!(2916);
+    collapsed_macro!(2917);
+    collapsed_macro!(2918);
+    collapsed_macro!(2919);
+    collapsed_macro!(2920);
+    collapsed_macro!(2921);
+    collapsed_macro!(2922);
+    collapsed_macro!(2923);
+    collapsed_macro!(2924);
+    collapsed_macro!(2925);
+    collapsed_macro!(2926);
+    collapsed_macro!(2927);
+    collapsed_macro!(2928);
+    collapsed_macro!(2929);
+    collapsed_macro!(2930);
+    collapsed_macro!(2931);
+    collapsed_macro!(2932);
+    collapsed_macro!(2933);
+    collapsed_macro!(2934);
+    collapsed_macro!(2935);
+    collapsed_macro!(2936);
+    collapsed_macro!(2937);
+    collapsed_macro!(2938);
+    collapsed_macro!(2939);
+    collapsed_macro!(2940);
+    collapsed_macro!(2941);
+    collapsed_macro!(2942);
+    collapsed_macro!(2943);
+    collapsed_macro!(2944);
+    collapsed_macro!(2945);
+    collapsed_macro!(2946);
+    collapsed_macro!(2947);
+    collapsed_macro!(2948);
+    collapsed_macro!(2949);
+    collapsed_macro!(2950);
+    collapsed_macro!(2951);
+    collapsed_macro!(2952);
+    collapsed_macro!(2953);
+    collapsed_macro!(2954);
+    collapsed_macro!(2955);
+    collapsed_macro!(2956);
+    collapsed_macro!(2957);
+    collapsed_macro!(2958);
+    collapsed_macro!(2959);
+    collapsed_macro!(2960);
+    collapsed_macro!(2961);
+    collapsed_macro!(2962);
+    collapsed_macro!(2963);
+    collapsed_macro!(2964);
+    collapsed_macro!(2965);
+    collapsed_macro!(2966);
+    collapsed_macro!(2967);
+    collapsed_macro!(2968);
+    collapsed_macro!(2969);
+    collapsed_macro!(2970);
+    collapsed_macro!(2971);
+    collapsed_macro!(2972);
+    collapsed_macro!(2973);
+    collapsed_macro!(2974);
+    collapsed_macro!(2975);
+    collapsed_macro!(2976);
+    collapsed_macro!(2977);
+    collapsed_macro!(2978);
+    collapsed_macro!(2979);
+    collapsed_macro!(2980);
+    collapsed_macro!(2981);
+    collapsed_macro!(2982);
+    collapsed_macro!(2983);
+    collapsed_macro!(2984);
+    collapsed_macro!(2985);
+    collapsed_macro!(2986);
+    collapsed_macro!(2987);
+    collapsed_macro!(2988);
+    collapsed_macro!(2989);
+    collapsed_macro!(2990);
+    collapsed_macro!(2991);
+    collapsed_macro!(2992);
+    collapsed_macro!(2993);
+    collapsed_macro!(2994);
+    collapsed_macro!(2995);
+    collapsed_macro!(2996);
+    collapsed_macro!(2997);
+    collapsed_macro!(2998);
+    collapsed_macro!(2999);
+    collapsed_macro!(3000);
+    collapsed_macro!(3001);
+    collapsed_macro!(3002);
+    collapsed_macro!(3003);
+    collapsed_macro!(3004);
+    collapsed_macro!(3005);
+    collapsed_macro!(3006);
+    collapsed_macro!(3007);
+    collapsed_macro!(3008);
+    collapsed_macro!(3009);
+    collapsed_macro!(3010);
+    collapsed_macro!(3011);
+    collapsed_macro!(3012);
+    collapsed_macro!(3013);
+    collapsed_macro!(3014);
+    collapsed_macro!(3015);
+    collapsed_macro!(3016);
+    collapsed_macro!(3017);
+    collapsed_macro!(3018);
+    collapsed_macro!(3019);
+    collapsed_macro!(3020);
+    collapsed_macro!(3021);
+    collapsed_macro!(3022);
+    collapsed_macro!(3023);
+    collapsed_macro!(3024);
+    collapsed_macro!(3025);
+    collapsed_macro!(3026);
+    collapsed_macro!(3027);
+    collapsed_macro!(3028);
+    collapsed_macro!(3029);
+    collapsed_macro!(3030);
+    collapsed_macro!(3031);
+    collapsed_macro!(3032);
+    collapsed_macro!(3033);
+    collapsed_macro!(3034);
+    collapsed_macro!(3035);
+    collapsed_macro!(3036);
+    collapsed_macro!(3037);
+    collapsed_macro!(3038);
+    collapsed_macro!(3039);
+    collapsed_macro!(3040);
+    collapsed_macro!(3041);
+    collapsed_macro!(3042);
+    collapsed_macro!(3043);
+    collapsed_macro!(3044);
+    collapsed_macro!(3045);
+    collapsed_macro!(3046);
+    collapsed_macro!(3047);
+    collapsed_macro!(3048);
+    collapsed_macro!(3049);
+    collapsed_macro!(3050);
+    collapsed_macro!(3051);
+    collapsed_macro!(3052);
+    collapsed_macro!(3053);
+    collapsed_macro!(3054);
+    collapsed_macro!(3055);
+    collapsed_macro!(3056);
+    collapsed_macro!(3057);
+    collapsed_macro!(3058);
+    collapsed_macro!(3059);
+    collapsed_macro!(3060);
+    collapsed_macro!(3061);
+    collapsed_macro!(3062);
+    collapsed_macro!(3063);
+    collapsed_macro!(3064);
+    collapsed_macro!(3065);
+    collapsed_macro!(3066);
+    collapsed_macro!(3067);
+    collapsed_macro!(3068);
+    collapsed_macro!(3069);
+    collapsed_macro!(3070);
+    collapsed_macro!(3071);
+    collapsed_macro!(3072);
+    collapsed_macro!(3073);
+    collapsed_macro!(3074);
+    collapsed_macro!(3075);
+    collapsed_macro!(3076);
+    collapsed_macro!(3077);
+    collapsed_macro!(3078);
+    collapsed_macro!(3079);
+    collapsed_macro!(3080);
+    collapsed_macro!(3081);
+    collapsed_macro!(3082);
+    collapsed_macro!(3083);
+    collapsed_macro!(3084);
+    collapsed_macro!(3085);
+    collapsed_macro!(3086);
+    collapsed_macro!(3087);
+    collapsed_macro!(3088);
+    collapsed_macro!(3089);
+    collapsed_macro!(3090);
+    collapsed_macro!(3091);
+    collapsed_macro!(3092);
+    collapsed_macro!(3093);
+    collapsed_macro!(3094);
+    collapsed_macro!(3095);
+    collapsed_macro!(3096);
+    collapsed_macro!(3097);
+    collapsed_macro!(3098);
+    collapsed_macro!(3099);
+    collapsed_macro!(3100);
+    collapsed_macro!(3101);
+    collapsed_macro!(3102);
+    collapsed_macro!(3103);
+    collapsed_macro!(3104);
+    collapsed_macro!(3105);
+    collapsed_macro!(3106);
+    collapsed_macro!(3107);
+    collapsed_macro!(3108);
+    collapsed_macro!(3109);
+    collapsed_macro!(3110);
+    collapsed_macro!(3111);
+    collapsed_macro!(3112);
+    collapsed_macro!(3113);
+    collapsed_macro!(3114);
+    collapsed_macro!(3115);
+    collapsed_macro!(3116);
+    collapsed_macro!(3117);
+    collapsed_macro!(3118);
+    collapsed_macro!(3119);
+    collapsed_macro!(3120);
+    collapsed_macro!(3121);
+    collapsed_macro!(3122);
+    collapsed_macro!(3123);
+    collapsed_macro!(3124);
+    collapsed_macro!(3125);
+    collapsed_macro!(3126);
+    collapsed_macro!(3127);
+    collapsed_macro!(3128);
+    collapsed_macro!(3129);
+    collapsed_macro!(3130);
+    collapsed_macro!(3131);
+    collapsed_macro!(3132);
+    collapsed_macro!(3133);
+    collapsed_macro!(3134);
+    collapsed_macro!(3135);
+    collapsed_macro!(3136);
+    collapsed_macro!(3137);
+    collapsed_macro!(3138);
+    collapsed_macro!(3139);
+    collapsed_macro!(3140);
+    collapsed_macro!(3141);
+    collapsed_macro!(3142);
+    collapsed_macro!(3143);
+    collapsed_macro!(3144);
+    collapsed_macro!(3145);
+    collapsed_macro!(3146);
+    collapsed_macro!(3147);
+    collapsed_macro!(3148);
+    collapsed_macro!(3149);
+    collapsed_macro!(3150);
+    collapsed_macro!(3151);
+    collapsed_macro!(3152);
+    collapsed_macro!(3153);
+    collapsed_macro!(3154);
+    collapsed_macro!(3155);
+    collapsed_macro!(3156);
+    collapsed_macro!(3157);
+    collapsed_macro!(3158);
+    collapsed_macro!(3159);
+    collapsed_macro!(3160);
+    collapsed_macro!(3161);
+    collapsed_macro!(3162);
+    collapsed_macro!(3163);
+    collapsed_macro!(3164);
+    collapsed_macro!(3165);
+    collapsed_macro!(3166);
+    collapsed_macro!(3167);
+    collapsed_macro!(3168);
+    collapsed_macro!(3169);
+    collapsed_macro!(3170);
+    collapsed_macro!(3171);
+    collapsed_macro!(3172);
+    collapsed_macro!(3173);
+    collapsed_macro!(3174);
+    collapsed_macro!(3175);
+    collapsed_macro!(3176);
+    collapsed_macro!(3177);
+    collapsed_macro!(3178);
+    collapsed_macro!(3179);
+    collapsed_macro!(3180);
+    collapsed_macro!(3181);
+    collapsed_macro!(3182);
+    collapsed_macro!(3183);
+    collapsed_macro!(3184);
+    collapsed_macro!(3185);
+    collapsed_macro!(3186);
+    collapsed_macro!(3187);
+    collapsed_macro!(3188);
+    collapsed_macro!(3189);
+    collapsed_macro!(3190);
+    collapsed_macro!(3191);
+    collapsed_macro!(3192);
+    collapsed_macro!(3193);
+    collapsed_macro!(3194);
+    collapsed_macro!(3195);
+    collapsed_macro!(3196);
+    collapsed_macro!(3197);
+    collapsed_macro!(3198);
+    collapsed_macro!(3199);
+    collapsed_macro!(3200);
+    collapsed_macro!(3201);
+    collapsed_macro!(3202);
+    collapsed_macro!(3203);
+    collapsed_macro!(3204);
+    collapsed_macro!(3205);
+    collapsed_macro!(3206);
+    collapsed_macro!(3207);
+    collapsed_macro!(3208);
+    collapsed_macro!(3209);
+    collapsed_macro!(3210);
+    collapsed_macro!(3211);
+    collapsed_macro!(3212);
+    collapsed_macro!(3213);
+    collapsed_macro!(3214);
+    collapsed_macro!(3215);
+    collapsed_macro!(3216);
+    collapsed_macro!(3217);
+    collapsed_macro!(3218);
+    collapsed_macro!(3219);
+    collapsed_macro!(3220);
+    collapsed_macro!(3221);
+    collapsed_macro!(3222);
+    collapsed_macro!(3223);
+    collapsed_macro!(3224);
+    collapsed_macro!(3225);
+    collapsed_macro!(3226);
+    collapsed_macro!(3227);
+    collapsed_macro!(3228);
+    collapsed_macro!(3229);
+    collapsed_macro!(3230);
+    collapsed_macro!(3231);
+    collapsed_macro!(3232);
+    collapsed_macro!(3233);
+    collapsed_macro!(3234);
+    collapsed_macro!(3235);
+    collapsed_macro!(3236);
+    collapsed_macro!(3237);
+    collapsed_macro!(3238);
+    collapsed_macro!(3239);
+    collapsed_macro!(3240);
+    collapsed_macro!(3241);
+    collapsed_macro!(3242);
+    collapsed_macro!(3243);
+    collapsed_macro!(3244);
+    collapsed_macro!(3245);
+    collapsed_macro!(3246);
+    collapsed_macro!(3247);
+    collapsed_macro!(3248);
+    collapsed_macro!(3249);
+    collapsed_macro!(3250);
+    collapsed_macro!(3251);
+    collapsed_macro!(3252);
+    collapsed_macro!(3253);
+    collapsed_macro!(3254);
+    collapsed_macro!(3255);
+    collapsed_macro!(3256);
+    collapsed_macro!(3257);
+    collapsed_macro!(3258);
+    collapsed_macro!(3259);
+    collapsed_macro!(3260);
+    collapsed_macro!(3261);
+    collapsed_macro!(3262);
+    collapsed_macro!(3263);
+    collapsed_macro!(3264);
+    collapsed_macro!(3265);
+    collapsed_macro!(3266);
+    collapsed_macro!(3267);
+    collapsed_macro!(3268);
+    collapsed_macro!(3269);
+    collapsed_macro!(3270);
+    collapsed_macro!(3271);
+    collapsed_macro!(3272);
+    collapsed_macro!(3273);
+    collapsed_macro!(3274);
+    collapsed_macro!(3275);
+    collapsed_macro!(3276);
+    collapsed_macro!(3277);
+    collapsed_macro!(3278);
+    collapsed_macro!(3279);
+    collapsed_macro!(3280);
+    collapsed_macro!(3281);
+    collapsed_macro!(3282);
+    collapsed_macro!(3283);
+    collapsed_macro!(3284);
+    collapsed_macro!(3285);
+    collapsed_macro!(3286);
+    collapsed_macro!(3287);
+    collapsed_macro!(3288);
+    collapsed_macro!(3289);
+    collapsed_macro!(3290);
+    collapsed_macro!(3291);
+    collapsed_macro!(3292);
+    collapsed_macro!(3293);
+    collapsed_macro!(3294);
+    collapsed_macro!(3295);
+    collapsed_macro!(3296);
+    collapsed_macro!(3297);
+    collapsed_macro!(3298);
+    collapsed_macro!(3299);
+    collapsed_macro!(3300);
+    collapsed_macro!(3301);
+    collapsed_macro!(3302);
+    collapsed_macro!(3303);
+    collapsed_macro!(3304);
+    collapsed_macro!(3305);
+    collapsed_macro!(3306);
+    collapsed_macro!(3307);
+    collapsed_macro!(3308);
+    collapsed_macro!(3309);
+    collapsed_macro!(3310);
+    collapsed_macro!(3311);
+    collapsed_macro!(3312);
+    collapsed_macro!(3313);
+    collapsed_macro!(3314);
+    collapsed_macro!(3315);
+    collapsed_macro!(3316);
+    collapsed_macro!(3317);
+    collapsed_macro!(3318);
+    collapsed_macro!(3319);
+    collapsed_macro!(3320);
+    collapsed_macro!(3321);
+    collapsed_macro!(3322);
+    collapsed_macro!(3323);
+    collapsed_macro!(3324);
+    collapsed_macro!(3325);
+    collapsed_macro!(3326);
+    collapsed_macro!(3327);
+    collapsed_macro!(3328);
+    collapsed_macro!(3329);
+    collapsed_macro!(3330);
+    collapsed_macro!(3331);
+    collapsed_macro!(3332);
+    collapsed_macro!(3333);
+    collapsed_macro!(3334);
+    collapsed_macro!(3335);
+    collapsed_macro!(3336);
+    collapsed_macro!(3337);
+    collapsed_macro!(3338);
+    collapsed_macro!(3339);
+    collapsed_macro!(3340);
+    collapsed_macro!(3341);
+    collapsed_macro!(3342);
+    collapsed_macro!(3343);
+    collapsed_macro!(3344);
+    collapsed_macro!(3345);
+    collapsed_macro!(3346);
+    collapsed_macro!(3347);
+    collapsed_macro!(3348);
+    collapsed_macro!(3349);
+    collapsed_macro!(3350);
+    collapsed_macro!(3351);
+    collapsed_macro!(3352);
+    collapsed_macro!(3353);
+    collapsed_macro!(3354);
+    collapsed_macro!(3355);
+    collapsed_macro!(3356);
+    collapsed_macro!(3357);
+    collapsed_macro!(3358);
+    collapsed_macro!(3359);
+    collapsed_macro!(3360);
+    collapsed_macro!(3361);
+    collapsed_macro!(3362);
+    collapsed_macro!(3363);
+    collapsed_macro!(3364);
+    collapsed_macro!(3365);
+    collapsed_macro!(3366);
+    collapsed_macro!(3367);
+    collapsed_macro!(3368);
+    collapsed_macro!(3369);
+    collapsed_macro!(3370);
+    collapsed_macro!(3371);
+    collapsed_macro!(3372);
+    collapsed_macro!(3373);
+    collapsed_macro!(3374);
+    collapsed_macro!(3375);
+    collapsed_macro!(3376);
+    collapsed_macro!(3377);
+    collapsed_macro!(3378);
+    collapsed_macro!(3379);
+    collapsed_macro!(3380);
+    collapsed_macro!(3381);
+    collapsed_macro!(3382);
+    collapsed_macro!(3383);
+    collapsed_macro!(3384);
+    collapsed_macro!(3385);
+    collapsed_macro!(3386);
+    collapsed_macro!(3387);
+    collapsed_macro!(3388);
+    collapsed_macro!(3389);
+    collapsed_macro!(3390);
+    collapsed_macro!(3391);
+    collapsed_macro!(3392);
+    collapsed_macro!(3393);
+    collapsed_macro!(3394);
+    collapsed_macro!(3395);
+    collapsed_macro!(3396);
+    collapsed_macro!(3397);
+    collapsed_macro!(3398);
+    collapsed_macro!(3399);
+    collapsed_macro!(3400);
+    collapsed_macro!(3401);
+    collapsed_macro!(3402);
+    collapsed_macro!(3403);
+    collapsed_macro!(3404);
+    collapsed_macro!(3405);
+    collapsed_macro!(3406);
+    collapsed_macro!(3407);
+    collapsed_macro!(3408);
+    collapsed_macro!(3409);
+    collapsed_macro!(3410);
+    collapsed_macro!(3411);
+    collapsed_macro!(3412);
+    collapsed_macro!(3413);
+    collapsed_macro!(3414);
+    collapsed_macro!(3415);
+    collapsed_macro!(3416);
+    collapsed_macro!(3417);
+    collapsed_macro!(3418);
+    collapsed_macro!(3419);
+    collapsed_macro!(3420);
+    collapsed_macro!(3421);
+    collapsed_macro!(3422);
+    collapsed_macro!(3423);
+    collapsed_macro!(3424);
+    collapsed_macro!(3425);
+    collapsed_macro!(3426);
+    collapsed_macro!(3427);
+    collapsed_macro!(3428);
+    collapsed_macro!(3429);
+    collapsed_macro!(3430);
+    collapsed_macro!(3431);
+    collapsed_macro!(3432);
+    collapsed_macro!(3433);
+    collapsed_macro!(3434);
+    collapsed_macro!(3435);
+    collapsed_macro!(3436);
+    collapsed_macro!(3437);
+    collapsed_macro!(3438);
+    collapsed_macro!(3439);
+    collapsed_macro!(3440);
+    collapsed_macro!(3441);
+    collapsed_macro!(3442);
+    collapsed_macro!(3443);
+    collapsed_macro!(3444);
+    collapsed_macro!(3445);
+    collapsed_macro!(3446);
+    collapsed_macro!(3447);
+    collapsed_macro!(3448);
+    collapsed_macro!(3449);
+    collapsed_macro!(3450);
+    collapsed_macro!(3451);
+    collapsed_macro!(3452);
+    collapsed_macro!(3453);
+    collapsed_macro!(3454);
+    collapsed_macro!(3455);
+    collapsed_macro!(3456);
+    collapsed_macro!(3457);
+    collapsed_macro!(3458);
+    collapsed_macro!(3459);
+    collapsed_macro!(3460);
+    collapsed_macro!(3461);
+    collapsed_macro!(3462);
+    collapsed_macro!(3463);
+    collapsed_macro!(3464);
+    collapsed_macro!(3465);
+    collapsed_macro!(3466);
+    collapsed_macro!(3467);
+    collapsed_macro!(3468);
+    collapsed_macro!(3469);
+    collapsed_macro!(3470);
+    collapsed_macro!(3471);
+    collapsed_macro!(3472);
+    collapsed_macro!(3473);
+    collapsed_macro!(3474);
+    collapsed_macro!(3475);
+    collapsed_macro!(3476);
+    collapsed_macro!(3477);
+    collapsed_macro!(3478);
+    collapsed_macro!(3479);
+    collapsed_macro!(3480);
+    collapsed_macro!(3481);
+    collapsed_macro!(3482);
+    collapsed_macro!(3483);
+    collapsed_macro!(3484);
+    collapsed_macro!(3485);
+    collapsed_macro!(3486);
+    collapsed_macro!(3487);
+    collapsed_macro!(3488);
+    collapsed_macro!(3489);
+    collapsed_macro!(3490);
+    collapsed_macro!(3491);
+    collapsed_macro!(3492);
+    collapsed_macro!(3493);
+    collapsed_macro!(3494);
+    collapsed_macro!(3495);
+    collapsed_macro!(3496);
+    collapsed_macro!(3497);
+    collapsed_macro!(3498);
+    collapsed_macro!(3499);
+    collapsed_macro!(3500);
+    collapsed_macro!(3501);
+    collapsed_macro!(3502);
+    collapsed_macro!(3503);
+    collapsed_macro!(3504);
+    collapsed_macro!(3505);
+    collapsed_macro!(3506);
+    collapsed_macro!(3507);
+    collapsed_macro!(3508);
+    collapsed_macro!(3509);
+    collapsed_macro!(3510);
+    collapsed_macro!(3511);
+    collapsed_macro!(3512);
+    collapsed_macro!(3513);
+    collapsed_macro!(3514);
+    collapsed_macro!(3515);
+    collapsed_macro!(3516);
+    collapsed_macro!(3517);
+    collapsed_macro!(3518);
+    collapsed_macro!(3519);
+    collapsed_macro!(3520);
+    collapsed_macro!(3521);
+    collapsed_macro!(3522);
+    collapsed_macro!(3523);
+    collapsed_macro!(3524);
+    collapsed_macro!(3525);
+    collapsed_macro!(3526);
+    collapsed_macro!(3527);
+    collapsed_macro!(3528);
+    collapsed_macro!(3529);
+    collapsed_macro!(3530);
+    collapsed_macro!(3531);
+    collapsed_macro!(3532);
+    collapsed_macro!(3533);
+    collapsed_macro!(3534);
+    collapsed_macro!(3535);
+    collapsed_macro!(3536);
+    collapsed_macro!(3537);
+    collapsed_macro!(3538);
+    collapsed_macro!(3539);
+    collapsed_macro!(3540);
+    collapsed_macro!(3541);
+    collapsed_macro!(3542);
+    collapsed_macro!(3543);
+    collapsed_macro!(3544);
+    collapsed_macro!(3545);
+    collapsed_macro!(3546);
+    collapsed_macro!(3547);
+    collapsed_macro!(3548);
+    collapsed_macro!(3549);
+    collapsed_macro!(3550);
+    collapsed_macro!(3551);
+    collapsed_macro!(3552);
+    collapsed_macro!(3553);
+    collapsed_macro!(3554);
+    collapsed_macro!(3555);
+    collapsed_macro!(3556);
+    collapsed_macro!(3557);
+    collapsed_macro!(3558);
+    collapsed_macro!(3559);
+    collapsed_macro!(3560);
+    collapsed_macro!(3561);
+    collapsed_macro!(3562);
+    collapsed_macro!(3563);
+    collapsed_macro!(3564);
+    collapsed_macro!(3565);
+    collapsed_macro!(3566);
+    collapsed_macro!(3567);
+    collapsed_macro!(3568);
+    collapsed_macro!(3569);
+    collapsed_macro!(3570);
+    collapsed_macro!(3571);
+    collapsed_macro!(3572);
+    collapsed_macro!(3573);
+    collapsed_macro!(3574);
+    collapsed_macro!(3575);
+    collapsed_macro!(3576);
+    collapsed_macro!(3577);
+    collapsed_macro!(3578);
+    collapsed_macro!(3579);
+    collapsed_macro!(3580);
+    collapsed_macro!(3581);
+    collapsed_macro!(3582);
+    collapsed_macro!(3583);
+    collapsed_macro!(3584);
+    collapsed_macro!(3585);
+    collapsed_macro!(3586);
+    collapsed_macro!(3587);
+    collapsed_macro!(3588);
+    collapsed_macro!(3589);
+    collapsed_macro!(3590);
+    collapsed_macro!(3591);
+    collapsed_macro!(3592);
+    collapsed_macro!(3593);
+    collapsed_macro!(3594);
+    collapsed_macro!(3595);
+    collapsed_macro!(3596);
+    collapsed_macro!(3597);
+    collapsed_macro!(3598);
+    collapsed_macro!(3599);
+    collapsed_macro!(3600);
+    collapsed_macro!(3601);
+    collapsed_macro!(3602);
+    collapsed_macro!(3603);
+    collapsed_macro!(3604);
+    collapsed_macro!(3605);
+    collapsed_macro!(3606);
+    collapsed_macro!(3607);
+    collapsed_macro!(3608);
+    collapsed_macro!(3609);
+    collapsed_macro!(3610);
+    collapsed_macro!(3611);
+    collapsed_macro!(3612);
+    collapsed_macro!(3613);
+    collapsed_macro!(3614);
+    collapsed_macro!(3615);
+    collapsed_macro!(3616);
+    collapsed_macro!(3617);
+    collapsed_macro!(3618);
+    collapsed_macro!(3619);
+    collapsed_macro!(3620);
+    collapsed_macro!(3621);
+    collapsed_macro!(3622);
+    collapsed_macro!(3623);
+    collapsed_macro!(3624);
+    collapsed_macro!(3625);
+    collapsed_macro!(3626);
+    collapsed_macro!(3627);
+    collapsed_macro!(3628);
+    collapsed_macro!(3629);
+    collapsed_macro!(3630);
+    collapsed_macro!(3631);
+    collapsed_macro!(3632);
+    collapsed_macro!(3633);
+    collapsed_macro!(3634);
+    collapsed_macro!(3635);
+    collapsed_macro!(3636);
+    collapsed_macro!(3637);
+    collapsed_macro!(3638);
+    collapsed_macro!(3639);
+    collapsed_macro!(3640);
+    collapsed_macro!(3641);
+    collapsed_macro!(3642);
+    collapsed_macro!(3643);
+    collapsed_macro!(3644);
+    collapsed_macro!(3645);
+    collapsed_macro!(3646);
+    collapsed_macro!(3647);
+    collapsed_macro!(3648);
+    collapsed_macro!(3649);
+    collapsed_macro!(3650);
+    collapsed_macro!(3651);
+    collapsed_macro!(3652);
+    collapsed_macro!(3653);
+    collapsed_macro!(3654);
+    collapsed_macro!(3655);
+    collapsed_macro!(3656);
+    collapsed_macro!(3657);
+    collapsed_macro!(3658);
+    collapsed_macro!(3659);
+    collapsed_macro!(3660);
+    collapsed_macro!(3661);
+    collapsed_macro!(3662);
+    collapsed_macro!(3663);
+    collapsed_macro!(3664);
+    collapsed_macro!(3665);
+    collapsed_macro!(3666);
+    collapsed_macro!(3667);
+    collapsed_macro!(3668);
+    collapsed_macro!(3669);
+    collapsed_macro!(3670);
+    collapsed_macro!(3671);
+    collapsed_macro!(3672);
+    collapsed_macro!(3673);
+    collapsed_macro!(3674);
+    collapsed_macro!(3675);
+    collapsed_macro!(3676);
+    collapsed_macro!(3677);
+    collapsed_macro!(3678);
+    collapsed_macro!(3679);
+    collapsed_macro!(3680);
+    collapsed_macro!(3681);
+    collapsed_macro!(3682);
+    collapsed_macro!(3683);
+    collapsed_macro!(3684);
+    collapsed_macro!(3685);
+    collapsed_macro!(3686);
+    collapsed_macro!(3687);
+    collapsed_macro!(3688);
+    collapsed_macro!(3689);
+    collapsed_macro!(3690);
+    collapsed_macro!(3691);
+    collapsed_macro!(3692);
+    collapsed_macro!(3693);
+    collapsed_macro!(3694);
+    collapsed_macro!(3695);
+    collapsed_macro!(3696);
+    collapsed_macro!(3697);
+    collapsed_macro!(3698);
+    collapsed_macro!(3699);
+    collapsed_macro!(3700);
+    collapsed_macro!(3701);
+    collapsed_macro!(3702);
+    collapsed_macro!(3703);
+    collapsed_macro!(3704);
+    collapsed_macro!(3705);
+    collapsed_macro!(3706);
+    collapsed_macro!(3707);
+    collapsed_macro!(3708);
+    collapsed_macro!(3709);
+    collapsed_macro!(3710);
+    collapsed_macro!(3711);
+    collapsed_macro!(3712);
+    collapsed_macro!(3713);
+    collapsed_macro!(3714);
+    collapsed_macro!(3715);
+    collapsed_macro!(3716);
+    collapsed_macro!(3717);
+    collapsed_macro!(3718);
+    collapsed_macro!(3719);
+    collapsed_macro!(3720);
+    collapsed_macro!(3721);
+    collapsed_macro!(3722);
+    collapsed_macro!(3723);
+    collapsed_macro!(3724);
+    collapsed_macro!(3725);
+    collapsed_macro!(3726);
+    collapsed_macro!(3727);
+    collapsed_macro!(3728);
+    collapsed_macro!(3729);
+    collapsed_macro!(3730);
+    collapsed_macro!(3731);
+    collapsed_macro!(3732);
+    collapsed_macro!(3733);
+    collapsed_macro!(3734);
+    collapsed_macro!(3735);
+    collapsed_macro!(3736);
+    collapsed_macro!(3737);
+    collapsed_macro!(3738);
+    collapsed_macro!(3739);
+    collapsed_macro!(3740);
+    collapsed_macro!(3741);
+    collapsed_macro!(3742);
+    collapsed_macro!(3743);
+    collapsed_macro!(3744);
+    collapsed_macro!(3745);
+    collapsed_macro!(3746);
+    collapsed_macro!(3747);
+    collapsed_macro!(3748);
+    collapsed_macro!(3749);
+    collapsed_macro!(3750);
+    collapsed_macro!(3751);
+    collapsed_macro!(3752);
+    collapsed_macro!(3753);
+    collapsed_macro!(3754);
+    collapsed_macro!(3755);
+    collapsed_macro!(3756);
+    collapsed_macro!(3757);
+    collapsed_macro!(3758);
+    collapsed_macro!(3759);
+    collapsed_macro!(3760);
+    collapsed_macro!(3761);
+    collapsed_macro!(3762);
+    collapsed_macro!(3763);
+    collapsed_macro!(3764);
+    collapsed_macro!(3765);
+    collapsed_macro!(3766);
+    collapsed_macro!(3767);
+    collapsed_macro!(3768);
+    collapsed_macro!(3769);
+    collapsed_macro!(3770);
+    collapsed_macro!(3771);
+    collapsed_macro!(3772);
+    collapsed_macro!(3773);
+    collapsed_macro!(3774);
+    collapsed_macro!(3775);
+    collapsed_macro!(3776);
+    collapsed_macro!(3777);
+    collapsed_macro!(3778);
+    collapsed_macro!(3779);
+    collapsed_macro!(3780);
+    collapsed_macro!(3781);
+    collapsed_macro!(3782);
+    collapsed_macro!(3783);
+    collapsed_macro!(3784);
+    collapsed_macro!(3785);
+    collapsed_macro!(3786);
+    collapsed_macro!(3787);
+    collapsed_macro!(3788);
+    collapsed_macro!(3789);
+    collapsed_macro!(3790);
+    collapsed_macro!(3791);
+    collapsed_macro!(3792);
+    collapsed_macro!(3793);
+    collapsed_macro!(3794);
+    collapsed_macro!(3795);
+    collapsed_macro!(3796);
+    collapsed_macro!(3797);
+    collapsed_macro!(3798);
+    collapsed_macro!(3799);
+    collapsed_macro!(3800);
+    collapsed_macro!(3801);
+    collapsed_macro!(3802);
+    collapsed_macro!(3803);
+    collapsed_macro!(3804);
+    collapsed_macro!(3805);
+    collapsed_macro!(3806);
+    collapsed_macro!(3807);
+    collapsed_macro!(3808);
+    collapsed_macro!(3809);
+    collapsed_macro!(3810);
+    collapsed_macro!(3811);
+    collapsed_macro!(3812);
+    collapsed_macro!(3813);
+    collapsed_macro!(3814);
+    collapsed_macro!(3815);
+    collapsed_macro!(3816);
+    collapsed_macro!(3817);
+    collapsed_macro!(3818);
+    collapsed_macro!(3819);
+    collapsed_macro!(3820);
+    collapsed_macro!(3821);
+    collapsed_macro!(3822);
+    collapsed_macro!(3823);
+    collapsed_macro!(3824);
+    collapsed_macro!(3825);
+    collapsed_macro!(3826);
+    collapsed_macro!(3827);
+    collapsed_macro!(3828);
+    collapsed_macro!(3829);
+    collapsed_macro!(3830);
+    collapsed_macro!(3831);
+    collapsed_macro!(3832);
+    collapsed_macro!(3833);
+    collapsed_macro!(3834);
+    collapsed_macro!(3835);
+    collapsed_macro!(3836);
+    collapsed_macro!(3837);
+    collapsed_macro!(3838);
+    collapsed_macro!(3839);
+    collapsed_macro!(3840);
+    collapsed_macro!(3841);
+    collapsed_macro!(3842);
+    collapsed_macro!(3843);
+    collapsed_macro!(3844);
+    collapsed_macro!(3845);
+    collapsed_macro!(3846);
+    collapsed_macro!(3847);
+    collapsed_macro!(3848);
+    collapsed_macro!(3849);
+    collapsed_macro!(3850);
+    collapsed_macro!(3851);
+    collapsed_macro!(3852);
+    collapsed_macro!(3853);
+    collapsed_macro!(3854);
+    collapsed_macro!(3855);
+    collapsed_macro!(3856);
+    collapsed_macro!(3857);
+    collapsed_macro!(3858);
+    collapsed_macro!(3859);
+    collapsed_macro!(3860);
+    collapsed_macro!(3861);
+    collapsed_macro!(3862);
+    collapsed_macro!(3863);
+    collapsed_macro!(3864);
+    collapsed_macro!(3865);
+    collapsed_macro!(3866);
+    collapsed_macro!(3867);
+    collapsed_macro!(3868);
+    collapsed_macro!(3869);
+    collapsed_macro!(3870);
+    collapsed_macro!(3871);
+    collapsed_macro!(3872);
+    collapsed_macro!(3873);
+    collapsed_macro!(3874);
+    collapsed_macro!(3875);
+    collapsed_macro!(3876);
+    collapsed_macro!(3877);
+    collapsed_macro!(3878);
+    collapsed_macro!(3879);
+    collapsed_macro!(3880);
+    collapsed_macro!(3881);
+    collapsed_macro!(3882);
+    collapsed_macro!(3883);
+    collapsed_macro!(3884);
+    collapsed_macro!(3885);
+    collapsed_macro!(3886);
+    collapsed_macro!(3887);
+    collapsed_macro!(3888);
+    collapsed_macro!(3889);
+    collapsed_macro!(3890);
+    collapsed_macro!(3891);
+    collapsed_macro!(3892);
+    collapsed_macro!(3893);
+    collapsed_macro!(3894);
+    collapsed_macro!(3895);
+    collapsed_macro!(3896);
+    collapsed_macro!(3897);
+    collapsed_macro!(3898);
+    collapsed_macro!(3899);
+    collapsed_macro!(3900);
+    collapsed_macro!(3901);
+    collapsed_macro!(3902);
+    collapsed_macro!(3903);
+    collapsed_macro!(3904);
+    collapsed_macro!(3905);
+    collapsed_macro!(3906);
+    collapsed_macro!(3907);
+    collapsed_macro!(3908);
+    collapsed_macro!(3909);
+    collapsed_macro!(3910);
+    collapsed_macro!(3911);
+    collapsed_macro!(3912);
+    collapsed_macro!(3913);
+    collapsed_macro!(3914);
+    collapsed_macro!(3915);
+    collapsed_macro!(3916);
+    collapsed_macro!(3917);
+    collapsed_macro!(3918);
+    collapsed_macro!(3919);
+    collapsed_macro!(3920);
+    collapsed_macro!(3921);
+    collapsed_macro!(3922);
+    collapsed_macro!(3923);
+    collapsed_macro!(3924);
+    collapsed_macro!(3925);
+    collapsed_macro!(3926);
+    collapsed_macro!(3927);
+    collapsed_macro!(3928);
+    collapsed_macro!(3929);
+    collapsed_macro!(3930);
+    collapsed_macro!(3931);
+    collapsed_macro!(3932);
+    collapsed_macro!(3933);
+    collapsed_macro!(3934);
+    collapsed_macro!(3935);
+    collapsed_macro!(3936);
+    collapsed_macro!(3937);
+    collapsed_macro!(3938);
+    collapsed_macro!(3939);
+    collapsed_macro!(3940);
+    collapsed_macro!(3941);
+    collapsed_macro!(3942);
+    collapsed_macro!(3943);
+    collapsed_macro!(3944);
+    collapsed_macro!(3945);
+    collapsed_macro!(3946);
+    collapsed_macro!(3947);
+    collapsed_macro!(3948);
+    collapsed_macro!(3949);
+    collapsed_macro!(3950);
+    collapsed_macro!(3951);
+    collapsed_macro!(3952);
+    collapsed_macro!(3953);
+    collapsed_macro!(3954);
+    collapsed_macro!(3955);
+    collapsed_macro!(3956);
+    collapsed_macro!(3957);
+    collapsed_macro!(3958);
+    collapsed_macro!(3959);
+    collapsed_macro!(3960);
+    collapsed_macro!(3961);
+    collapsed_macro!(3962);
+    collapsed_macro!(3963);
+    collapsed_macro!(3964);
+    collapsed_macro!(3965);
+    collapsed_macro!(3966);
+    collapsed_macro!(3967);
+    collapsed_macro!(3968);
+    collapsed_macro!(3969);
+    collapsed_macro!(3970);
+    collapsed_macro!(3971);
+    collapsed_macro!(3972);
+    collapsed_macro!(3973);
+    collapsed_macro!(3974);
+    collapsed_macro!(3975);
+    collapsed_macro!(3976);
+    collapsed_macro!(3977);
+    collapsed_macro!(3978);
+    collapsed_macro!(3979);
+    collapsed_macro!(3980);
+    collapsed_macro!(3981);
+    collapsed_macro!(3982);
+    collapsed_macro!(3983);
+    collapsed_macro!(3984);
+    collapsed_macro!(3985);
+    collapsed_macro!(3986);
+    collapsed_macro!(3987);
+    collapsed_macro!(3988);
+    collapsed_macro!(3989);
+    collapsed_macro!(3990);
+    collapsed_macro!(3991);
+    collapsed_macro!(3992);
+    collapsed_macro!(3993);
+    collapsed_macro!(3994);
+    collapsed_macro!(3995);
+    collapsed_macro!(3996);
+    collapsed_macro!(3997);
+    collapsed_macro!(3998);
+    collapsed_macro!(3999);
+    collapsed_macro!(4000);
+    collapsed_macro!(4001);
+    collapsed_macro!(4002);
+    collapsed_macro!(4003);
+    collapsed_macro!(4004);
+    collapsed_macro!(4005);
+    collapsed_macro!(4006);
+    collapsed_macro!(4007);
+    collapsed_macro!(4008);
+    collapsed_macro!(4009);
+    collapsed_macro!(4010);
+    collapsed_macro!(4011);
+    collapsed_macro!(4012);
+    collapsed_macro!(4013);
+    collapsed_macro!(4014);
+    collapsed_macro!(4015);
+    collapsed_macro!(4016);
+    collapsed_macro!(4017);
+    collapsed_macro!(4018);
+    collapsed_macro!(4019);
+    collapsed_macro!(4020);
+    collapsed_macro!(4021);
+    collapsed_macro!(4022);
+    collapsed_macro!(4023);
+    collapsed_macro!(4024);
+    collapsed_macro!(4025);
+    collapsed_macro!(4026);
+    collapsed_macro!(4027);
+    collapsed_macro!(4028);
+    collapsed_macro!(4029);
+    collapsed_macro!(4030);
+    collapsed_macro!(4031);
+    collapsed_macro!(4032);
+    collapsed_macro!(4033);
+    collapsed_macro!(4034);
+    collapsed_macro!(4035);
+    collapsed_macro!(4036);
+    collapsed_macro!(4037);
+    collapsed_macro!(4038);
+    collapsed_macro!(4039);
+    collapsed_macro!(4040);
+    collapsed_macro!(4041);
+    collapsed_macro!(4042);
+    collapsed_macro!(4043);
+    collapsed_macro!(4044);
+    collapsed_macro!(4045);
+    collapsed_macro!(4046);
+    collapsed_macro!(4047);
+    collapsed_macro!(4048);
+    collapsed_macro!(4049);
+    collapsed_macro!(4050);
+    collapsed_macro!(4051);
+    collapsed_macro!(4052);
+    collapsed_macro!(4053);
+    collapsed_macro!(4054);
+    collapsed_macro!(4055);
+    collapsed_macro!(4056);
+    collapsed_macro!(4057);
+    collapsed_macro!(4058);
+    collapsed_macro!(4059);
+    collapsed_macro!(4060);
+    collapsed_macro!(4061);
+    collapsed_macro!(4062);
+    collapsed_macro!(4063);
+    collapsed_macro!(4064);
+    collapsed_macro!(4065);
+    collapsed_macro!(4066);
+    collapsed_macro!(4067);
+    collapsed_macro!(4068);
+    collapsed_macro!(4069);
+    collapsed_macro!(4070);
+    collapsed_macro!(4071);
+    collapsed_macro!(4072);
+    collapsed_macro!(4073);
+    collapsed_macro!(4074);
+    collapsed_macro!(4075);
+    collapsed_macro!(4076);
+    collapsed_macro!(4077);
+    collapsed_macro!(4078);
+    collapsed_macro!(4079);
+    collapsed_macro!(4080);
+    collapsed_macro!(4081);
+    collapsed_macro!(4082);
+    collapsed_macro!(4083);
+    collapsed_macro!(4084);
+    collapsed_macro!(4085);
+    collapsed_macro!(4086);
+    collapsed_macro!(4087);
+    collapsed_macro!(4088);
+    collapsed_macro!(4089);
+    collapsed_macro!(4090);
+    collapsed_macro!(4091);
+    collapsed_macro!(4092);
+    collapsed_macro!(4093);
+    collapsed_macro!(4094);
+    collapsed_macro!(4095);
+    collapsed_macro!(4096);
+    collapsed_macro!(4097);
+}
+
+fn main() {
+    collapsed_debuginfo();
+}
diff --git a/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs
new file mode 100644
index 00000000000..3696ed37a20
--- /dev/null
+++ b/tests/ui/debuginfo/debuginfo-inline-callsite-location-macro-2.rs
@@ -0,0 +1,4122 @@
+//@ check-pass
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline
+//@ ignore-msvc
+// ignore-tidy-filelength
+
+#[derive(Default)]
+struct Something {}
+
+macro_rules! simple_macro {
+    ($code:expr) => {
+        // Important to use a function here, so it can be inlined
+        // at the MIR stage.
+        Something::default()
+    }
+}
+
+fn uncollapsed_debuginfo() {
+    // LLVM allows 12 bits for encoding discriminators, so 4096+1 calls to a
+    // MIR-inlined function will exhaust it. At that point we will start
+    // dropping debug info (and tracing::warn!).
+    simple_macro!(1);
+    simple_macro!(2);
+    simple_macro!(3);
+    simple_macro!(4);
+    simple_macro!(5);
+    simple_macro!(6);
+    simple_macro!(7);
+    simple_macro!(8);
+    simple_macro!(9);
+    simple_macro!(10);
+    simple_macro!(11);
+    simple_macro!(12);
+    simple_macro!(13);
+    simple_macro!(14);
+    simple_macro!(15);
+    simple_macro!(16);
+    simple_macro!(17);
+    simple_macro!(18);
+    simple_macro!(19);
+    simple_macro!(20);
+    simple_macro!(21);
+    simple_macro!(22);
+    simple_macro!(23);
+    simple_macro!(24);
+    simple_macro!(25);
+    simple_macro!(26);
+    simple_macro!(27);
+    simple_macro!(28);
+    simple_macro!(29);
+    simple_macro!(30);
+    simple_macro!(31);
+    simple_macro!(32);
+    simple_macro!(33);
+    simple_macro!(34);
+    simple_macro!(35);
+    simple_macro!(36);
+    simple_macro!(37);
+    simple_macro!(38);
+    simple_macro!(39);
+    simple_macro!(40);
+    simple_macro!(41);
+    simple_macro!(42);
+    simple_macro!(43);
+    simple_macro!(44);
+    simple_macro!(45);
+    simple_macro!(46);
+    simple_macro!(47);
+    simple_macro!(48);
+    simple_macro!(49);
+    simple_macro!(50);
+    simple_macro!(51);
+    simple_macro!(52);
+    simple_macro!(53);
+    simple_macro!(54);
+    simple_macro!(55);
+    simple_macro!(56);
+    simple_macro!(57);
+    simple_macro!(58);
+    simple_macro!(59);
+    simple_macro!(60);
+    simple_macro!(61);
+    simple_macro!(62);
+    simple_macro!(63);
+    simple_macro!(64);
+    simple_macro!(65);
+    simple_macro!(66);
+    simple_macro!(67);
+    simple_macro!(68);
+    simple_macro!(69);
+    simple_macro!(70);
+    simple_macro!(71);
+    simple_macro!(72);
+    simple_macro!(73);
+    simple_macro!(74);
+    simple_macro!(75);
+    simple_macro!(76);
+    simple_macro!(77);
+    simple_macro!(78);
+    simple_macro!(79);
+    simple_macro!(80);
+    simple_macro!(81);
+    simple_macro!(82);
+    simple_macro!(83);
+    simple_macro!(84);
+    simple_macro!(85);
+    simple_macro!(86);
+    simple_macro!(87);
+    simple_macro!(88);
+    simple_macro!(89);
+    simple_macro!(90);
+    simple_macro!(91);
+    simple_macro!(92);
+    simple_macro!(93);
+    simple_macro!(94);
+    simple_macro!(95);
+    simple_macro!(96);
+    simple_macro!(97);
+    simple_macro!(98);
+    simple_macro!(99);
+    simple_macro!(100);
+    simple_macro!(101);
+    simple_macro!(102);
+    simple_macro!(103);
+    simple_macro!(104);
+    simple_macro!(105);
+    simple_macro!(106);
+    simple_macro!(107);
+    simple_macro!(108);
+    simple_macro!(109);
+    simple_macro!(110);
+    simple_macro!(111);
+    simple_macro!(112);
+    simple_macro!(113);
+    simple_macro!(114);
+    simple_macro!(115);
+    simple_macro!(116);
+    simple_macro!(117);
+    simple_macro!(118);
+    simple_macro!(119);
+    simple_macro!(120);
+    simple_macro!(121);
+    simple_macro!(122);
+    simple_macro!(123);
+    simple_macro!(124);
+    simple_macro!(125);
+    simple_macro!(126);
+    simple_macro!(127);
+    simple_macro!(128);
+    simple_macro!(129);
+    simple_macro!(130);
+    simple_macro!(131);
+    simple_macro!(132);
+    simple_macro!(133);
+    simple_macro!(134);
+    simple_macro!(135);
+    simple_macro!(136);
+    simple_macro!(137);
+    simple_macro!(138);
+    simple_macro!(139);
+    simple_macro!(140);
+    simple_macro!(141);
+    simple_macro!(142);
+    simple_macro!(143);
+    simple_macro!(144);
+    simple_macro!(145);
+    simple_macro!(146);
+    simple_macro!(147);
+    simple_macro!(148);
+    simple_macro!(149);
+    simple_macro!(150);
+    simple_macro!(151);
+    simple_macro!(152);
+    simple_macro!(153);
+    simple_macro!(154);
+    simple_macro!(155);
+    simple_macro!(156);
+    simple_macro!(157);
+    simple_macro!(158);
+    simple_macro!(159);
+    simple_macro!(160);
+    simple_macro!(161);
+    simple_macro!(162);
+    simple_macro!(163);
+    simple_macro!(164);
+    simple_macro!(165);
+    simple_macro!(166);
+    simple_macro!(167);
+    simple_macro!(168);
+    simple_macro!(169);
+    simple_macro!(170);
+    simple_macro!(171);
+    simple_macro!(172);
+    simple_macro!(173);
+    simple_macro!(174);
+    simple_macro!(175);
+    simple_macro!(176);
+    simple_macro!(177);
+    simple_macro!(178);
+    simple_macro!(179);
+    simple_macro!(180);
+    simple_macro!(181);
+    simple_macro!(182);
+    simple_macro!(183);
+    simple_macro!(184);
+    simple_macro!(185);
+    simple_macro!(186);
+    simple_macro!(187);
+    simple_macro!(188);
+    simple_macro!(189);
+    simple_macro!(190);
+    simple_macro!(191);
+    simple_macro!(192);
+    simple_macro!(193);
+    simple_macro!(194);
+    simple_macro!(195);
+    simple_macro!(196);
+    simple_macro!(197);
+    simple_macro!(198);
+    simple_macro!(199);
+    simple_macro!(200);
+    simple_macro!(201);
+    simple_macro!(202);
+    simple_macro!(203);
+    simple_macro!(204);
+    simple_macro!(205);
+    simple_macro!(206);
+    simple_macro!(207);
+    simple_macro!(208);
+    simple_macro!(209);
+    simple_macro!(210);
+    simple_macro!(211);
+    simple_macro!(212);
+    simple_macro!(213);
+    simple_macro!(214);
+    simple_macro!(215);
+    simple_macro!(216);
+    simple_macro!(217);
+    simple_macro!(218);
+    simple_macro!(219);
+    simple_macro!(220);
+    simple_macro!(221);
+    simple_macro!(222);
+    simple_macro!(223);
+    simple_macro!(224);
+    simple_macro!(225);
+    simple_macro!(226);
+    simple_macro!(227);
+    simple_macro!(228);
+    simple_macro!(229);
+    simple_macro!(230);
+    simple_macro!(231);
+    simple_macro!(232);
+    simple_macro!(233);
+    simple_macro!(234);
+    simple_macro!(235);
+    simple_macro!(236);
+    simple_macro!(237);
+    simple_macro!(238);
+    simple_macro!(239);
+    simple_macro!(240);
+    simple_macro!(241);
+    simple_macro!(242);
+    simple_macro!(243);
+    simple_macro!(244);
+    simple_macro!(245);
+    simple_macro!(246);
+    simple_macro!(247);
+    simple_macro!(248);
+    simple_macro!(249);
+    simple_macro!(250);
+    simple_macro!(251);
+    simple_macro!(252);
+    simple_macro!(253);
+    simple_macro!(254);
+    simple_macro!(255);
+    simple_macro!(256);
+    simple_macro!(257);
+    simple_macro!(258);
+    simple_macro!(259);
+    simple_macro!(260);
+    simple_macro!(261);
+    simple_macro!(262);
+    simple_macro!(263);
+    simple_macro!(264);
+    simple_macro!(265);
+    simple_macro!(266);
+    simple_macro!(267);
+    simple_macro!(268);
+    simple_macro!(269);
+    simple_macro!(270);
+    simple_macro!(271);
+    simple_macro!(272);
+    simple_macro!(273);
+    simple_macro!(274);
+    simple_macro!(275);
+    simple_macro!(276);
+    simple_macro!(277);
+    simple_macro!(278);
+    simple_macro!(279);
+    simple_macro!(280);
+    simple_macro!(281);
+    simple_macro!(282);
+    simple_macro!(283);
+    simple_macro!(284);
+    simple_macro!(285);
+    simple_macro!(286);
+    simple_macro!(287);
+    simple_macro!(288);
+    simple_macro!(289);
+    simple_macro!(290);
+    simple_macro!(291);
+    simple_macro!(292);
+    simple_macro!(293);
+    simple_macro!(294);
+    simple_macro!(295);
+    simple_macro!(296);
+    simple_macro!(297);
+    simple_macro!(298);
+    simple_macro!(299);
+    simple_macro!(300);
+    simple_macro!(301);
+    simple_macro!(302);
+    simple_macro!(303);
+    simple_macro!(304);
+    simple_macro!(305);
+    simple_macro!(306);
+    simple_macro!(307);
+    simple_macro!(308);
+    simple_macro!(309);
+    simple_macro!(310);
+    simple_macro!(311);
+    simple_macro!(312);
+    simple_macro!(313);
+    simple_macro!(314);
+    simple_macro!(315);
+    simple_macro!(316);
+    simple_macro!(317);
+    simple_macro!(318);
+    simple_macro!(319);
+    simple_macro!(320);
+    simple_macro!(321);
+    simple_macro!(322);
+    simple_macro!(323);
+    simple_macro!(324);
+    simple_macro!(325);
+    simple_macro!(326);
+    simple_macro!(327);
+    simple_macro!(328);
+    simple_macro!(329);
+    simple_macro!(330);
+    simple_macro!(331);
+    simple_macro!(332);
+    simple_macro!(333);
+    simple_macro!(334);
+    simple_macro!(335);
+    simple_macro!(336);
+    simple_macro!(337);
+    simple_macro!(338);
+    simple_macro!(339);
+    simple_macro!(340);
+    simple_macro!(341);
+    simple_macro!(342);
+    simple_macro!(343);
+    simple_macro!(344);
+    simple_macro!(345);
+    simple_macro!(346);
+    simple_macro!(347);
+    simple_macro!(348);
+    simple_macro!(349);
+    simple_macro!(350);
+    simple_macro!(351);
+    simple_macro!(352);
+    simple_macro!(353);
+    simple_macro!(354);
+    simple_macro!(355);
+    simple_macro!(356);
+    simple_macro!(357);
+    simple_macro!(358);
+    simple_macro!(359);
+    simple_macro!(360);
+    simple_macro!(361);
+    simple_macro!(362);
+    simple_macro!(363);
+    simple_macro!(364);
+    simple_macro!(365);
+    simple_macro!(366);
+    simple_macro!(367);
+    simple_macro!(368);
+    simple_macro!(369);
+    simple_macro!(370);
+    simple_macro!(371);
+    simple_macro!(372);
+    simple_macro!(373);
+    simple_macro!(374);
+    simple_macro!(375);
+    simple_macro!(376);
+    simple_macro!(377);
+    simple_macro!(378);
+    simple_macro!(379);
+    simple_macro!(380);
+    simple_macro!(381);
+    simple_macro!(382);
+    simple_macro!(383);
+    simple_macro!(384);
+    simple_macro!(385);
+    simple_macro!(386);
+    simple_macro!(387);
+    simple_macro!(388);
+    simple_macro!(389);
+    simple_macro!(390);
+    simple_macro!(391);
+    simple_macro!(392);
+    simple_macro!(393);
+    simple_macro!(394);
+    simple_macro!(395);
+    simple_macro!(396);
+    simple_macro!(397);
+    simple_macro!(398);
+    simple_macro!(399);
+    simple_macro!(400);
+    simple_macro!(401);
+    simple_macro!(402);
+    simple_macro!(403);
+    simple_macro!(404);
+    simple_macro!(405);
+    simple_macro!(406);
+    simple_macro!(407);
+    simple_macro!(408);
+    simple_macro!(409);
+    simple_macro!(410);
+    simple_macro!(411);
+    simple_macro!(412);
+    simple_macro!(413);
+    simple_macro!(414);
+    simple_macro!(415);
+    simple_macro!(416);
+    simple_macro!(417);
+    simple_macro!(418);
+    simple_macro!(419);
+    simple_macro!(420);
+    simple_macro!(421);
+    simple_macro!(422);
+    simple_macro!(423);
+    simple_macro!(424);
+    simple_macro!(425);
+    simple_macro!(426);
+    simple_macro!(427);
+    simple_macro!(428);
+    simple_macro!(429);
+    simple_macro!(430);
+    simple_macro!(431);
+    simple_macro!(432);
+    simple_macro!(433);
+    simple_macro!(434);
+    simple_macro!(435);
+    simple_macro!(436);
+    simple_macro!(437);
+    simple_macro!(438);
+    simple_macro!(439);
+    simple_macro!(440);
+    simple_macro!(441);
+    simple_macro!(442);
+    simple_macro!(443);
+    simple_macro!(444);
+    simple_macro!(445);
+    simple_macro!(446);
+    simple_macro!(447);
+    simple_macro!(448);
+    simple_macro!(449);
+    simple_macro!(450);
+    simple_macro!(451);
+    simple_macro!(452);
+    simple_macro!(453);
+    simple_macro!(454);
+    simple_macro!(455);
+    simple_macro!(456);
+    simple_macro!(457);
+    simple_macro!(458);
+    simple_macro!(459);
+    simple_macro!(460);
+    simple_macro!(461);
+    simple_macro!(462);
+    simple_macro!(463);
+    simple_macro!(464);
+    simple_macro!(465);
+    simple_macro!(466);
+    simple_macro!(467);
+    simple_macro!(468);
+    simple_macro!(469);
+    simple_macro!(470);
+    simple_macro!(471);
+    simple_macro!(472);
+    simple_macro!(473);
+    simple_macro!(474);
+    simple_macro!(475);
+    simple_macro!(476);
+    simple_macro!(477);
+    simple_macro!(478);
+    simple_macro!(479);
+    simple_macro!(480);
+    simple_macro!(481);
+    simple_macro!(482);
+    simple_macro!(483);
+    simple_macro!(484);
+    simple_macro!(485);
+    simple_macro!(486);
+    simple_macro!(487);
+    simple_macro!(488);
+    simple_macro!(489);
+    simple_macro!(490);
+    simple_macro!(491);
+    simple_macro!(492);
+    simple_macro!(493);
+    simple_macro!(494);
+    simple_macro!(495);
+    simple_macro!(496);
+    simple_macro!(497);
+    simple_macro!(498);
+    simple_macro!(499);
+    simple_macro!(500);
+    simple_macro!(501);
+    simple_macro!(502);
+    simple_macro!(503);
+    simple_macro!(504);
+    simple_macro!(505);
+    simple_macro!(506);
+    simple_macro!(507);
+    simple_macro!(508);
+    simple_macro!(509);
+    simple_macro!(510);
+    simple_macro!(511);
+    simple_macro!(512);
+    simple_macro!(513);
+    simple_macro!(514);
+    simple_macro!(515);
+    simple_macro!(516);
+    simple_macro!(517);
+    simple_macro!(518);
+    simple_macro!(519);
+    simple_macro!(520);
+    simple_macro!(521);
+    simple_macro!(522);
+    simple_macro!(523);
+    simple_macro!(524);
+    simple_macro!(525);
+    simple_macro!(526);
+    simple_macro!(527);
+    simple_macro!(528);
+    simple_macro!(529);
+    simple_macro!(530);
+    simple_macro!(531);
+    simple_macro!(532);
+    simple_macro!(533);
+    simple_macro!(534);
+    simple_macro!(535);
+    simple_macro!(536);
+    simple_macro!(537);
+    simple_macro!(538);
+    simple_macro!(539);
+    simple_macro!(540);
+    simple_macro!(541);
+    simple_macro!(542);
+    simple_macro!(543);
+    simple_macro!(544);
+    simple_macro!(545);
+    simple_macro!(546);
+    simple_macro!(547);
+    simple_macro!(548);
+    simple_macro!(549);
+    simple_macro!(550);
+    simple_macro!(551);
+    simple_macro!(552);
+    simple_macro!(553);
+    simple_macro!(554);
+    simple_macro!(555);
+    simple_macro!(556);
+    simple_macro!(557);
+    simple_macro!(558);
+    simple_macro!(559);
+    simple_macro!(560);
+    simple_macro!(561);
+    simple_macro!(562);
+    simple_macro!(563);
+    simple_macro!(564);
+    simple_macro!(565);
+    simple_macro!(566);
+    simple_macro!(567);
+    simple_macro!(568);
+    simple_macro!(569);
+    simple_macro!(570);
+    simple_macro!(571);
+    simple_macro!(572);
+    simple_macro!(573);
+    simple_macro!(574);
+    simple_macro!(575);
+    simple_macro!(576);
+    simple_macro!(577);
+    simple_macro!(578);
+    simple_macro!(579);
+    simple_macro!(580);
+    simple_macro!(581);
+    simple_macro!(582);
+    simple_macro!(583);
+    simple_macro!(584);
+    simple_macro!(585);
+    simple_macro!(586);
+    simple_macro!(587);
+    simple_macro!(588);
+    simple_macro!(589);
+    simple_macro!(590);
+    simple_macro!(591);
+    simple_macro!(592);
+    simple_macro!(593);
+    simple_macro!(594);
+    simple_macro!(595);
+    simple_macro!(596);
+    simple_macro!(597);
+    simple_macro!(598);
+    simple_macro!(599);
+    simple_macro!(600);
+    simple_macro!(601);
+    simple_macro!(602);
+    simple_macro!(603);
+    simple_macro!(604);
+    simple_macro!(605);
+    simple_macro!(606);
+    simple_macro!(607);
+    simple_macro!(608);
+    simple_macro!(609);
+    simple_macro!(610);
+    simple_macro!(611);
+    simple_macro!(612);
+    simple_macro!(613);
+    simple_macro!(614);
+    simple_macro!(615);
+    simple_macro!(616);
+    simple_macro!(617);
+    simple_macro!(618);
+    simple_macro!(619);
+    simple_macro!(620);
+    simple_macro!(621);
+    simple_macro!(622);
+    simple_macro!(623);
+    simple_macro!(624);
+    simple_macro!(625);
+    simple_macro!(626);
+    simple_macro!(627);
+    simple_macro!(628);
+    simple_macro!(629);
+    simple_macro!(630);
+    simple_macro!(631);
+    simple_macro!(632);
+    simple_macro!(633);
+    simple_macro!(634);
+    simple_macro!(635);
+    simple_macro!(636);
+    simple_macro!(637);
+    simple_macro!(638);
+    simple_macro!(639);
+    simple_macro!(640);
+    simple_macro!(641);
+    simple_macro!(642);
+    simple_macro!(643);
+    simple_macro!(644);
+    simple_macro!(645);
+    simple_macro!(646);
+    simple_macro!(647);
+    simple_macro!(648);
+    simple_macro!(649);
+    simple_macro!(650);
+    simple_macro!(651);
+    simple_macro!(652);
+    simple_macro!(653);
+    simple_macro!(654);
+    simple_macro!(655);
+    simple_macro!(656);
+    simple_macro!(657);
+    simple_macro!(658);
+    simple_macro!(659);
+    simple_macro!(660);
+    simple_macro!(661);
+    simple_macro!(662);
+    simple_macro!(663);
+    simple_macro!(664);
+    simple_macro!(665);
+    simple_macro!(666);
+    simple_macro!(667);
+    simple_macro!(668);
+    simple_macro!(669);
+    simple_macro!(670);
+    simple_macro!(671);
+    simple_macro!(672);
+    simple_macro!(673);
+    simple_macro!(674);
+    simple_macro!(675);
+    simple_macro!(676);
+    simple_macro!(677);
+    simple_macro!(678);
+    simple_macro!(679);
+    simple_macro!(680);
+    simple_macro!(681);
+    simple_macro!(682);
+    simple_macro!(683);
+    simple_macro!(684);
+    simple_macro!(685);
+    simple_macro!(686);
+    simple_macro!(687);
+    simple_macro!(688);
+    simple_macro!(689);
+    simple_macro!(690);
+    simple_macro!(691);
+    simple_macro!(692);
+    simple_macro!(693);
+    simple_macro!(694);
+    simple_macro!(695);
+    simple_macro!(696);
+    simple_macro!(697);
+    simple_macro!(698);
+    simple_macro!(699);
+    simple_macro!(700);
+    simple_macro!(701);
+    simple_macro!(702);
+    simple_macro!(703);
+    simple_macro!(704);
+    simple_macro!(705);
+    simple_macro!(706);
+    simple_macro!(707);
+    simple_macro!(708);
+    simple_macro!(709);
+    simple_macro!(710);
+    simple_macro!(711);
+    simple_macro!(712);
+    simple_macro!(713);
+    simple_macro!(714);
+    simple_macro!(715);
+    simple_macro!(716);
+    simple_macro!(717);
+    simple_macro!(718);
+    simple_macro!(719);
+    simple_macro!(720);
+    simple_macro!(721);
+    simple_macro!(722);
+    simple_macro!(723);
+    simple_macro!(724);
+    simple_macro!(725);
+    simple_macro!(726);
+    simple_macro!(727);
+    simple_macro!(728);
+    simple_macro!(729);
+    simple_macro!(730);
+    simple_macro!(731);
+    simple_macro!(732);
+    simple_macro!(733);
+    simple_macro!(734);
+    simple_macro!(735);
+    simple_macro!(736);
+    simple_macro!(737);
+    simple_macro!(738);
+    simple_macro!(739);
+    simple_macro!(740);
+    simple_macro!(741);
+    simple_macro!(742);
+    simple_macro!(743);
+    simple_macro!(744);
+    simple_macro!(745);
+    simple_macro!(746);
+    simple_macro!(747);
+    simple_macro!(748);
+    simple_macro!(749);
+    simple_macro!(750);
+    simple_macro!(751);
+    simple_macro!(752);
+    simple_macro!(753);
+    simple_macro!(754);
+    simple_macro!(755);
+    simple_macro!(756);
+    simple_macro!(757);
+    simple_macro!(758);
+    simple_macro!(759);
+    simple_macro!(760);
+    simple_macro!(761);
+    simple_macro!(762);
+    simple_macro!(763);
+    simple_macro!(764);
+    simple_macro!(765);
+    simple_macro!(766);
+    simple_macro!(767);
+    simple_macro!(768);
+    simple_macro!(769);
+    simple_macro!(770);
+    simple_macro!(771);
+    simple_macro!(772);
+    simple_macro!(773);
+    simple_macro!(774);
+    simple_macro!(775);
+    simple_macro!(776);
+    simple_macro!(777);
+    simple_macro!(778);
+    simple_macro!(779);
+    simple_macro!(780);
+    simple_macro!(781);
+    simple_macro!(782);
+    simple_macro!(783);
+    simple_macro!(784);
+    simple_macro!(785);
+    simple_macro!(786);
+    simple_macro!(787);
+    simple_macro!(788);
+    simple_macro!(789);
+    simple_macro!(790);
+    simple_macro!(791);
+    simple_macro!(792);
+    simple_macro!(793);
+    simple_macro!(794);
+    simple_macro!(795);
+    simple_macro!(796);
+    simple_macro!(797);
+    simple_macro!(798);
+    simple_macro!(799);
+    simple_macro!(800);
+    simple_macro!(801);
+    simple_macro!(802);
+    simple_macro!(803);
+    simple_macro!(804);
+    simple_macro!(805);
+    simple_macro!(806);
+    simple_macro!(807);
+    simple_macro!(808);
+    simple_macro!(809);
+    simple_macro!(810);
+    simple_macro!(811);
+    simple_macro!(812);
+    simple_macro!(813);
+    simple_macro!(814);
+    simple_macro!(815);
+    simple_macro!(816);
+    simple_macro!(817);
+    simple_macro!(818);
+    simple_macro!(819);
+    simple_macro!(820);
+    simple_macro!(821);
+    simple_macro!(822);
+    simple_macro!(823);
+    simple_macro!(824);
+    simple_macro!(825);
+    simple_macro!(826);
+    simple_macro!(827);
+    simple_macro!(828);
+    simple_macro!(829);
+    simple_macro!(830);
+    simple_macro!(831);
+    simple_macro!(832);
+    simple_macro!(833);
+    simple_macro!(834);
+    simple_macro!(835);
+    simple_macro!(836);
+    simple_macro!(837);
+    simple_macro!(838);
+    simple_macro!(839);
+    simple_macro!(840);
+    simple_macro!(841);
+    simple_macro!(842);
+    simple_macro!(843);
+    simple_macro!(844);
+    simple_macro!(845);
+    simple_macro!(846);
+    simple_macro!(847);
+    simple_macro!(848);
+    simple_macro!(849);
+    simple_macro!(850);
+    simple_macro!(851);
+    simple_macro!(852);
+    simple_macro!(853);
+    simple_macro!(854);
+    simple_macro!(855);
+    simple_macro!(856);
+    simple_macro!(857);
+    simple_macro!(858);
+    simple_macro!(859);
+    simple_macro!(860);
+    simple_macro!(861);
+    simple_macro!(862);
+    simple_macro!(863);
+    simple_macro!(864);
+    simple_macro!(865);
+    simple_macro!(866);
+    simple_macro!(867);
+    simple_macro!(868);
+    simple_macro!(869);
+    simple_macro!(870);
+    simple_macro!(871);
+    simple_macro!(872);
+    simple_macro!(873);
+    simple_macro!(874);
+    simple_macro!(875);
+    simple_macro!(876);
+    simple_macro!(877);
+    simple_macro!(878);
+    simple_macro!(879);
+    simple_macro!(880);
+    simple_macro!(881);
+    simple_macro!(882);
+    simple_macro!(883);
+    simple_macro!(884);
+    simple_macro!(885);
+    simple_macro!(886);
+    simple_macro!(887);
+    simple_macro!(888);
+    simple_macro!(889);
+    simple_macro!(890);
+    simple_macro!(891);
+    simple_macro!(892);
+    simple_macro!(893);
+    simple_macro!(894);
+    simple_macro!(895);
+    simple_macro!(896);
+    simple_macro!(897);
+    simple_macro!(898);
+    simple_macro!(899);
+    simple_macro!(900);
+    simple_macro!(901);
+    simple_macro!(902);
+    simple_macro!(903);
+    simple_macro!(904);
+    simple_macro!(905);
+    simple_macro!(906);
+    simple_macro!(907);
+    simple_macro!(908);
+    simple_macro!(909);
+    simple_macro!(910);
+    simple_macro!(911);
+    simple_macro!(912);
+    simple_macro!(913);
+    simple_macro!(914);
+    simple_macro!(915);
+    simple_macro!(916);
+    simple_macro!(917);
+    simple_macro!(918);
+    simple_macro!(919);
+    simple_macro!(920);
+    simple_macro!(921);
+    simple_macro!(922);
+    simple_macro!(923);
+    simple_macro!(924);
+    simple_macro!(925);
+    simple_macro!(926);
+    simple_macro!(927);
+    simple_macro!(928);
+    simple_macro!(929);
+    simple_macro!(930);
+    simple_macro!(931);
+    simple_macro!(932);
+    simple_macro!(933);
+    simple_macro!(934);
+    simple_macro!(935);
+    simple_macro!(936);
+    simple_macro!(937);
+    simple_macro!(938);
+    simple_macro!(939);
+    simple_macro!(940);
+    simple_macro!(941);
+    simple_macro!(942);
+    simple_macro!(943);
+    simple_macro!(944);
+    simple_macro!(945);
+    simple_macro!(946);
+    simple_macro!(947);
+    simple_macro!(948);
+    simple_macro!(949);
+    simple_macro!(950);
+    simple_macro!(951);
+    simple_macro!(952);
+    simple_macro!(953);
+    simple_macro!(954);
+    simple_macro!(955);
+    simple_macro!(956);
+    simple_macro!(957);
+    simple_macro!(958);
+    simple_macro!(959);
+    simple_macro!(960);
+    simple_macro!(961);
+    simple_macro!(962);
+    simple_macro!(963);
+    simple_macro!(964);
+    simple_macro!(965);
+    simple_macro!(966);
+    simple_macro!(967);
+    simple_macro!(968);
+    simple_macro!(969);
+    simple_macro!(970);
+    simple_macro!(971);
+    simple_macro!(972);
+    simple_macro!(973);
+    simple_macro!(974);
+    simple_macro!(975);
+    simple_macro!(976);
+    simple_macro!(977);
+    simple_macro!(978);
+    simple_macro!(979);
+    simple_macro!(980);
+    simple_macro!(981);
+    simple_macro!(982);
+    simple_macro!(983);
+    simple_macro!(984);
+    simple_macro!(985);
+    simple_macro!(986);
+    simple_macro!(987);
+    simple_macro!(988);
+    simple_macro!(989);
+    simple_macro!(990);
+    simple_macro!(991);
+    simple_macro!(992);
+    simple_macro!(993);
+    simple_macro!(994);
+    simple_macro!(995);
+    simple_macro!(996);
+    simple_macro!(997);
+    simple_macro!(998);
+    simple_macro!(999);
+    simple_macro!(1000);
+    simple_macro!(1001);
+    simple_macro!(1002);
+    simple_macro!(1003);
+    simple_macro!(1004);
+    simple_macro!(1005);
+    simple_macro!(1006);
+    simple_macro!(1007);
+    simple_macro!(1008);
+    simple_macro!(1009);
+    simple_macro!(1010);
+    simple_macro!(1011);
+    simple_macro!(1012);
+    simple_macro!(1013);
+    simple_macro!(1014);
+    simple_macro!(1015);
+    simple_macro!(1016);
+    simple_macro!(1017);
+    simple_macro!(1018);
+    simple_macro!(1019);
+    simple_macro!(1020);
+    simple_macro!(1021);
+    simple_macro!(1022);
+    simple_macro!(1023);
+    simple_macro!(1024);
+    simple_macro!(1025);
+    simple_macro!(1026);
+    simple_macro!(1027);
+    simple_macro!(1028);
+    simple_macro!(1029);
+    simple_macro!(1030);
+    simple_macro!(1031);
+    simple_macro!(1032);
+    simple_macro!(1033);
+    simple_macro!(1034);
+    simple_macro!(1035);
+    simple_macro!(1036);
+    simple_macro!(1037);
+    simple_macro!(1038);
+    simple_macro!(1039);
+    simple_macro!(1040);
+    simple_macro!(1041);
+    simple_macro!(1042);
+    simple_macro!(1043);
+    simple_macro!(1044);
+    simple_macro!(1045);
+    simple_macro!(1046);
+    simple_macro!(1047);
+    simple_macro!(1048);
+    simple_macro!(1049);
+    simple_macro!(1050);
+    simple_macro!(1051);
+    simple_macro!(1052);
+    simple_macro!(1053);
+    simple_macro!(1054);
+    simple_macro!(1055);
+    simple_macro!(1056);
+    simple_macro!(1057);
+    simple_macro!(1058);
+    simple_macro!(1059);
+    simple_macro!(1060);
+    simple_macro!(1061);
+    simple_macro!(1062);
+    simple_macro!(1063);
+    simple_macro!(1064);
+    simple_macro!(1065);
+    simple_macro!(1066);
+    simple_macro!(1067);
+    simple_macro!(1068);
+    simple_macro!(1069);
+    simple_macro!(1070);
+    simple_macro!(1071);
+    simple_macro!(1072);
+    simple_macro!(1073);
+    simple_macro!(1074);
+    simple_macro!(1075);
+    simple_macro!(1076);
+    simple_macro!(1077);
+    simple_macro!(1078);
+    simple_macro!(1079);
+    simple_macro!(1080);
+    simple_macro!(1081);
+    simple_macro!(1082);
+    simple_macro!(1083);
+    simple_macro!(1084);
+    simple_macro!(1085);
+    simple_macro!(1086);
+    simple_macro!(1087);
+    simple_macro!(1088);
+    simple_macro!(1089);
+    simple_macro!(1090);
+    simple_macro!(1091);
+    simple_macro!(1092);
+    simple_macro!(1093);
+    simple_macro!(1094);
+    simple_macro!(1095);
+    simple_macro!(1096);
+    simple_macro!(1097);
+    simple_macro!(1098);
+    simple_macro!(1099);
+    simple_macro!(1100);
+    simple_macro!(1101);
+    simple_macro!(1102);
+    simple_macro!(1103);
+    simple_macro!(1104);
+    simple_macro!(1105);
+    simple_macro!(1106);
+    simple_macro!(1107);
+    simple_macro!(1108);
+    simple_macro!(1109);
+    simple_macro!(1110);
+    simple_macro!(1111);
+    simple_macro!(1112);
+    simple_macro!(1113);
+    simple_macro!(1114);
+    simple_macro!(1115);
+    simple_macro!(1116);
+    simple_macro!(1117);
+    simple_macro!(1118);
+    simple_macro!(1119);
+    simple_macro!(1120);
+    simple_macro!(1121);
+    simple_macro!(1122);
+    simple_macro!(1123);
+    simple_macro!(1124);
+    simple_macro!(1125);
+    simple_macro!(1126);
+    simple_macro!(1127);
+    simple_macro!(1128);
+    simple_macro!(1129);
+    simple_macro!(1130);
+    simple_macro!(1131);
+    simple_macro!(1132);
+    simple_macro!(1133);
+    simple_macro!(1134);
+    simple_macro!(1135);
+    simple_macro!(1136);
+    simple_macro!(1137);
+    simple_macro!(1138);
+    simple_macro!(1139);
+    simple_macro!(1140);
+    simple_macro!(1141);
+    simple_macro!(1142);
+    simple_macro!(1143);
+    simple_macro!(1144);
+    simple_macro!(1145);
+    simple_macro!(1146);
+    simple_macro!(1147);
+    simple_macro!(1148);
+    simple_macro!(1149);
+    simple_macro!(1150);
+    simple_macro!(1151);
+    simple_macro!(1152);
+    simple_macro!(1153);
+    simple_macro!(1154);
+    simple_macro!(1155);
+    simple_macro!(1156);
+    simple_macro!(1157);
+    simple_macro!(1158);
+    simple_macro!(1159);
+    simple_macro!(1160);
+    simple_macro!(1161);
+    simple_macro!(1162);
+    simple_macro!(1163);
+    simple_macro!(1164);
+    simple_macro!(1165);
+    simple_macro!(1166);
+    simple_macro!(1167);
+    simple_macro!(1168);
+    simple_macro!(1169);
+    simple_macro!(1170);
+    simple_macro!(1171);
+    simple_macro!(1172);
+    simple_macro!(1173);
+    simple_macro!(1174);
+    simple_macro!(1175);
+    simple_macro!(1176);
+    simple_macro!(1177);
+    simple_macro!(1178);
+    simple_macro!(1179);
+    simple_macro!(1180);
+    simple_macro!(1181);
+    simple_macro!(1182);
+    simple_macro!(1183);
+    simple_macro!(1184);
+    simple_macro!(1185);
+    simple_macro!(1186);
+    simple_macro!(1187);
+    simple_macro!(1188);
+    simple_macro!(1189);
+    simple_macro!(1190);
+    simple_macro!(1191);
+    simple_macro!(1192);
+    simple_macro!(1193);
+    simple_macro!(1194);
+    simple_macro!(1195);
+    simple_macro!(1196);
+    simple_macro!(1197);
+    simple_macro!(1198);
+    simple_macro!(1199);
+    simple_macro!(1200);
+    simple_macro!(1201);
+    simple_macro!(1202);
+    simple_macro!(1203);
+    simple_macro!(1204);
+    simple_macro!(1205);
+    simple_macro!(1206);
+    simple_macro!(1207);
+    simple_macro!(1208);
+    simple_macro!(1209);
+    simple_macro!(1210);
+    simple_macro!(1211);
+    simple_macro!(1212);
+    simple_macro!(1213);
+    simple_macro!(1214);
+    simple_macro!(1215);
+    simple_macro!(1216);
+    simple_macro!(1217);
+    simple_macro!(1218);
+    simple_macro!(1219);
+    simple_macro!(1220);
+    simple_macro!(1221);
+    simple_macro!(1222);
+    simple_macro!(1223);
+    simple_macro!(1224);
+    simple_macro!(1225);
+    simple_macro!(1226);
+    simple_macro!(1227);
+    simple_macro!(1228);
+    simple_macro!(1229);
+    simple_macro!(1230);
+    simple_macro!(1231);
+    simple_macro!(1232);
+    simple_macro!(1233);
+    simple_macro!(1234);
+    simple_macro!(1235);
+    simple_macro!(1236);
+    simple_macro!(1237);
+    simple_macro!(1238);
+    simple_macro!(1239);
+    simple_macro!(1240);
+    simple_macro!(1241);
+    simple_macro!(1242);
+    simple_macro!(1243);
+    simple_macro!(1244);
+    simple_macro!(1245);
+    simple_macro!(1246);
+    simple_macro!(1247);
+    simple_macro!(1248);
+    simple_macro!(1249);
+    simple_macro!(1250);
+    simple_macro!(1251);
+    simple_macro!(1252);
+    simple_macro!(1253);
+    simple_macro!(1254);
+    simple_macro!(1255);
+    simple_macro!(1256);
+    simple_macro!(1257);
+    simple_macro!(1258);
+    simple_macro!(1259);
+    simple_macro!(1260);
+    simple_macro!(1261);
+    simple_macro!(1262);
+    simple_macro!(1263);
+    simple_macro!(1264);
+    simple_macro!(1265);
+    simple_macro!(1266);
+    simple_macro!(1267);
+    simple_macro!(1268);
+    simple_macro!(1269);
+    simple_macro!(1270);
+    simple_macro!(1271);
+    simple_macro!(1272);
+    simple_macro!(1273);
+    simple_macro!(1274);
+    simple_macro!(1275);
+    simple_macro!(1276);
+    simple_macro!(1277);
+    simple_macro!(1278);
+    simple_macro!(1279);
+    simple_macro!(1280);
+    simple_macro!(1281);
+    simple_macro!(1282);
+    simple_macro!(1283);
+    simple_macro!(1284);
+    simple_macro!(1285);
+    simple_macro!(1286);
+    simple_macro!(1287);
+    simple_macro!(1288);
+    simple_macro!(1289);
+    simple_macro!(1290);
+    simple_macro!(1291);
+    simple_macro!(1292);
+    simple_macro!(1293);
+    simple_macro!(1294);
+    simple_macro!(1295);
+    simple_macro!(1296);
+    simple_macro!(1297);
+    simple_macro!(1298);
+    simple_macro!(1299);
+    simple_macro!(1300);
+    simple_macro!(1301);
+    simple_macro!(1302);
+    simple_macro!(1303);
+    simple_macro!(1304);
+    simple_macro!(1305);
+    simple_macro!(1306);
+    simple_macro!(1307);
+    simple_macro!(1308);
+    simple_macro!(1309);
+    simple_macro!(1310);
+    simple_macro!(1311);
+    simple_macro!(1312);
+    simple_macro!(1313);
+    simple_macro!(1314);
+    simple_macro!(1315);
+    simple_macro!(1316);
+    simple_macro!(1317);
+    simple_macro!(1318);
+    simple_macro!(1319);
+    simple_macro!(1320);
+    simple_macro!(1321);
+    simple_macro!(1322);
+    simple_macro!(1323);
+    simple_macro!(1324);
+    simple_macro!(1325);
+    simple_macro!(1326);
+    simple_macro!(1327);
+    simple_macro!(1328);
+    simple_macro!(1329);
+    simple_macro!(1330);
+    simple_macro!(1331);
+    simple_macro!(1332);
+    simple_macro!(1333);
+    simple_macro!(1334);
+    simple_macro!(1335);
+    simple_macro!(1336);
+    simple_macro!(1337);
+    simple_macro!(1338);
+    simple_macro!(1339);
+    simple_macro!(1340);
+    simple_macro!(1341);
+    simple_macro!(1342);
+    simple_macro!(1343);
+    simple_macro!(1344);
+    simple_macro!(1345);
+    simple_macro!(1346);
+    simple_macro!(1347);
+    simple_macro!(1348);
+    simple_macro!(1349);
+    simple_macro!(1350);
+    simple_macro!(1351);
+    simple_macro!(1352);
+    simple_macro!(1353);
+    simple_macro!(1354);
+    simple_macro!(1355);
+    simple_macro!(1356);
+    simple_macro!(1357);
+    simple_macro!(1358);
+    simple_macro!(1359);
+    simple_macro!(1360);
+    simple_macro!(1361);
+    simple_macro!(1362);
+    simple_macro!(1363);
+    simple_macro!(1364);
+    simple_macro!(1365);
+    simple_macro!(1366);
+    simple_macro!(1367);
+    simple_macro!(1368);
+    simple_macro!(1369);
+    simple_macro!(1370);
+    simple_macro!(1371);
+    simple_macro!(1372);
+    simple_macro!(1373);
+    simple_macro!(1374);
+    simple_macro!(1375);
+    simple_macro!(1376);
+    simple_macro!(1377);
+    simple_macro!(1378);
+    simple_macro!(1379);
+    simple_macro!(1380);
+    simple_macro!(1381);
+    simple_macro!(1382);
+    simple_macro!(1383);
+    simple_macro!(1384);
+    simple_macro!(1385);
+    simple_macro!(1386);
+    simple_macro!(1387);
+    simple_macro!(1388);
+    simple_macro!(1389);
+    simple_macro!(1390);
+    simple_macro!(1391);
+    simple_macro!(1392);
+    simple_macro!(1393);
+    simple_macro!(1394);
+    simple_macro!(1395);
+    simple_macro!(1396);
+    simple_macro!(1397);
+    simple_macro!(1398);
+    simple_macro!(1399);
+    simple_macro!(1400);
+    simple_macro!(1401);
+    simple_macro!(1402);
+    simple_macro!(1403);
+    simple_macro!(1404);
+    simple_macro!(1405);
+    simple_macro!(1406);
+    simple_macro!(1407);
+    simple_macro!(1408);
+    simple_macro!(1409);
+    simple_macro!(1410);
+    simple_macro!(1411);
+    simple_macro!(1412);
+    simple_macro!(1413);
+    simple_macro!(1414);
+    simple_macro!(1415);
+    simple_macro!(1416);
+    simple_macro!(1417);
+    simple_macro!(1418);
+    simple_macro!(1419);
+    simple_macro!(1420);
+    simple_macro!(1421);
+    simple_macro!(1422);
+    simple_macro!(1423);
+    simple_macro!(1424);
+    simple_macro!(1425);
+    simple_macro!(1426);
+    simple_macro!(1427);
+    simple_macro!(1428);
+    simple_macro!(1429);
+    simple_macro!(1430);
+    simple_macro!(1431);
+    simple_macro!(1432);
+    simple_macro!(1433);
+    simple_macro!(1434);
+    simple_macro!(1435);
+    simple_macro!(1436);
+    simple_macro!(1437);
+    simple_macro!(1438);
+    simple_macro!(1439);
+    simple_macro!(1440);
+    simple_macro!(1441);
+    simple_macro!(1442);
+    simple_macro!(1443);
+    simple_macro!(1444);
+    simple_macro!(1445);
+    simple_macro!(1446);
+    simple_macro!(1447);
+    simple_macro!(1448);
+    simple_macro!(1449);
+    simple_macro!(1450);
+    simple_macro!(1451);
+    simple_macro!(1452);
+    simple_macro!(1453);
+    simple_macro!(1454);
+    simple_macro!(1455);
+    simple_macro!(1456);
+    simple_macro!(1457);
+    simple_macro!(1458);
+    simple_macro!(1459);
+    simple_macro!(1460);
+    simple_macro!(1461);
+    simple_macro!(1462);
+    simple_macro!(1463);
+    simple_macro!(1464);
+    simple_macro!(1465);
+    simple_macro!(1466);
+    simple_macro!(1467);
+    simple_macro!(1468);
+    simple_macro!(1469);
+    simple_macro!(1470);
+    simple_macro!(1471);
+    simple_macro!(1472);
+    simple_macro!(1473);
+    simple_macro!(1474);
+    simple_macro!(1475);
+    simple_macro!(1476);
+    simple_macro!(1477);
+    simple_macro!(1478);
+    simple_macro!(1479);
+    simple_macro!(1480);
+    simple_macro!(1481);
+    simple_macro!(1482);
+    simple_macro!(1483);
+    simple_macro!(1484);
+    simple_macro!(1485);
+    simple_macro!(1486);
+    simple_macro!(1487);
+    simple_macro!(1488);
+    simple_macro!(1489);
+    simple_macro!(1490);
+    simple_macro!(1491);
+    simple_macro!(1492);
+    simple_macro!(1493);
+    simple_macro!(1494);
+    simple_macro!(1495);
+    simple_macro!(1496);
+    simple_macro!(1497);
+    simple_macro!(1498);
+    simple_macro!(1499);
+    simple_macro!(1500);
+    simple_macro!(1501);
+    simple_macro!(1502);
+    simple_macro!(1503);
+    simple_macro!(1504);
+    simple_macro!(1505);
+    simple_macro!(1506);
+    simple_macro!(1507);
+    simple_macro!(1508);
+    simple_macro!(1509);
+    simple_macro!(1510);
+    simple_macro!(1511);
+    simple_macro!(1512);
+    simple_macro!(1513);
+    simple_macro!(1514);
+    simple_macro!(1515);
+    simple_macro!(1516);
+    simple_macro!(1517);
+    simple_macro!(1518);
+    simple_macro!(1519);
+    simple_macro!(1520);
+    simple_macro!(1521);
+    simple_macro!(1522);
+    simple_macro!(1523);
+    simple_macro!(1524);
+    simple_macro!(1525);
+    simple_macro!(1526);
+    simple_macro!(1527);
+    simple_macro!(1528);
+    simple_macro!(1529);
+    simple_macro!(1530);
+    simple_macro!(1531);
+    simple_macro!(1532);
+    simple_macro!(1533);
+    simple_macro!(1534);
+    simple_macro!(1535);
+    simple_macro!(1536);
+    simple_macro!(1537);
+    simple_macro!(1538);
+    simple_macro!(1539);
+    simple_macro!(1540);
+    simple_macro!(1541);
+    simple_macro!(1542);
+    simple_macro!(1543);
+    simple_macro!(1544);
+    simple_macro!(1545);
+    simple_macro!(1546);
+    simple_macro!(1547);
+    simple_macro!(1548);
+    simple_macro!(1549);
+    simple_macro!(1550);
+    simple_macro!(1551);
+    simple_macro!(1552);
+    simple_macro!(1553);
+    simple_macro!(1554);
+    simple_macro!(1555);
+    simple_macro!(1556);
+    simple_macro!(1557);
+    simple_macro!(1558);
+    simple_macro!(1559);
+    simple_macro!(1560);
+    simple_macro!(1561);
+    simple_macro!(1562);
+    simple_macro!(1563);
+    simple_macro!(1564);
+    simple_macro!(1565);
+    simple_macro!(1566);
+    simple_macro!(1567);
+    simple_macro!(1568);
+    simple_macro!(1569);
+    simple_macro!(1570);
+    simple_macro!(1571);
+    simple_macro!(1572);
+    simple_macro!(1573);
+    simple_macro!(1574);
+    simple_macro!(1575);
+    simple_macro!(1576);
+    simple_macro!(1577);
+    simple_macro!(1578);
+    simple_macro!(1579);
+    simple_macro!(1580);
+    simple_macro!(1581);
+    simple_macro!(1582);
+    simple_macro!(1583);
+    simple_macro!(1584);
+    simple_macro!(1585);
+    simple_macro!(1586);
+    simple_macro!(1587);
+    simple_macro!(1588);
+    simple_macro!(1589);
+    simple_macro!(1590);
+    simple_macro!(1591);
+    simple_macro!(1592);
+    simple_macro!(1593);
+    simple_macro!(1594);
+    simple_macro!(1595);
+    simple_macro!(1596);
+    simple_macro!(1597);
+    simple_macro!(1598);
+    simple_macro!(1599);
+    simple_macro!(1600);
+    simple_macro!(1601);
+    simple_macro!(1602);
+    simple_macro!(1603);
+    simple_macro!(1604);
+    simple_macro!(1605);
+    simple_macro!(1606);
+    simple_macro!(1607);
+    simple_macro!(1608);
+    simple_macro!(1609);
+    simple_macro!(1610);
+    simple_macro!(1611);
+    simple_macro!(1612);
+    simple_macro!(1613);
+    simple_macro!(1614);
+    simple_macro!(1615);
+    simple_macro!(1616);
+    simple_macro!(1617);
+    simple_macro!(1618);
+    simple_macro!(1619);
+    simple_macro!(1620);
+    simple_macro!(1621);
+    simple_macro!(1622);
+    simple_macro!(1623);
+    simple_macro!(1624);
+    simple_macro!(1625);
+    simple_macro!(1626);
+    simple_macro!(1627);
+    simple_macro!(1628);
+    simple_macro!(1629);
+    simple_macro!(1630);
+    simple_macro!(1631);
+    simple_macro!(1632);
+    simple_macro!(1633);
+    simple_macro!(1634);
+    simple_macro!(1635);
+    simple_macro!(1636);
+    simple_macro!(1637);
+    simple_macro!(1638);
+    simple_macro!(1639);
+    simple_macro!(1640);
+    simple_macro!(1641);
+    simple_macro!(1642);
+    simple_macro!(1643);
+    simple_macro!(1644);
+    simple_macro!(1645);
+    simple_macro!(1646);
+    simple_macro!(1647);
+    simple_macro!(1648);
+    simple_macro!(1649);
+    simple_macro!(1650);
+    simple_macro!(1651);
+    simple_macro!(1652);
+    simple_macro!(1653);
+    simple_macro!(1654);
+    simple_macro!(1655);
+    simple_macro!(1656);
+    simple_macro!(1657);
+    simple_macro!(1658);
+    simple_macro!(1659);
+    simple_macro!(1660);
+    simple_macro!(1661);
+    simple_macro!(1662);
+    simple_macro!(1663);
+    simple_macro!(1664);
+    simple_macro!(1665);
+    simple_macro!(1666);
+    simple_macro!(1667);
+    simple_macro!(1668);
+    simple_macro!(1669);
+    simple_macro!(1670);
+    simple_macro!(1671);
+    simple_macro!(1672);
+    simple_macro!(1673);
+    simple_macro!(1674);
+    simple_macro!(1675);
+    simple_macro!(1676);
+    simple_macro!(1677);
+    simple_macro!(1678);
+    simple_macro!(1679);
+    simple_macro!(1680);
+    simple_macro!(1681);
+    simple_macro!(1682);
+    simple_macro!(1683);
+    simple_macro!(1684);
+    simple_macro!(1685);
+    simple_macro!(1686);
+    simple_macro!(1687);
+    simple_macro!(1688);
+    simple_macro!(1689);
+    simple_macro!(1690);
+    simple_macro!(1691);
+    simple_macro!(1692);
+    simple_macro!(1693);
+    simple_macro!(1694);
+    simple_macro!(1695);
+    simple_macro!(1696);
+    simple_macro!(1697);
+    simple_macro!(1698);
+    simple_macro!(1699);
+    simple_macro!(1700);
+    simple_macro!(1701);
+    simple_macro!(1702);
+    simple_macro!(1703);
+    simple_macro!(1704);
+    simple_macro!(1705);
+    simple_macro!(1706);
+    simple_macro!(1707);
+    simple_macro!(1708);
+    simple_macro!(1709);
+    simple_macro!(1710);
+    simple_macro!(1711);
+    simple_macro!(1712);
+    simple_macro!(1713);
+    simple_macro!(1714);
+    simple_macro!(1715);
+    simple_macro!(1716);
+    simple_macro!(1717);
+    simple_macro!(1718);
+    simple_macro!(1719);
+    simple_macro!(1720);
+    simple_macro!(1721);
+    simple_macro!(1722);
+    simple_macro!(1723);
+    simple_macro!(1724);
+    simple_macro!(1725);
+    simple_macro!(1726);
+    simple_macro!(1727);
+    simple_macro!(1728);
+    simple_macro!(1729);
+    simple_macro!(1730);
+    simple_macro!(1731);
+    simple_macro!(1732);
+    simple_macro!(1733);
+    simple_macro!(1734);
+    simple_macro!(1735);
+    simple_macro!(1736);
+    simple_macro!(1737);
+    simple_macro!(1738);
+    simple_macro!(1739);
+    simple_macro!(1740);
+    simple_macro!(1741);
+    simple_macro!(1742);
+    simple_macro!(1743);
+    simple_macro!(1744);
+    simple_macro!(1745);
+    simple_macro!(1746);
+    simple_macro!(1747);
+    simple_macro!(1748);
+    simple_macro!(1749);
+    simple_macro!(1750);
+    simple_macro!(1751);
+    simple_macro!(1752);
+    simple_macro!(1753);
+    simple_macro!(1754);
+    simple_macro!(1755);
+    simple_macro!(1756);
+    simple_macro!(1757);
+    simple_macro!(1758);
+    simple_macro!(1759);
+    simple_macro!(1760);
+    simple_macro!(1761);
+    simple_macro!(1762);
+    simple_macro!(1763);
+    simple_macro!(1764);
+    simple_macro!(1765);
+    simple_macro!(1766);
+    simple_macro!(1767);
+    simple_macro!(1768);
+    simple_macro!(1769);
+    simple_macro!(1770);
+    simple_macro!(1771);
+    simple_macro!(1772);
+    simple_macro!(1773);
+    simple_macro!(1774);
+    simple_macro!(1775);
+    simple_macro!(1776);
+    simple_macro!(1777);
+    simple_macro!(1778);
+    simple_macro!(1779);
+    simple_macro!(1780);
+    simple_macro!(1781);
+    simple_macro!(1782);
+    simple_macro!(1783);
+    simple_macro!(1784);
+    simple_macro!(1785);
+    simple_macro!(1786);
+    simple_macro!(1787);
+    simple_macro!(1788);
+    simple_macro!(1789);
+    simple_macro!(1790);
+    simple_macro!(1791);
+    simple_macro!(1792);
+    simple_macro!(1793);
+    simple_macro!(1794);
+    simple_macro!(1795);
+    simple_macro!(1796);
+    simple_macro!(1797);
+    simple_macro!(1798);
+    simple_macro!(1799);
+    simple_macro!(1800);
+    simple_macro!(1801);
+    simple_macro!(1802);
+    simple_macro!(1803);
+    simple_macro!(1804);
+    simple_macro!(1805);
+    simple_macro!(1806);
+    simple_macro!(1807);
+    simple_macro!(1808);
+    simple_macro!(1809);
+    simple_macro!(1810);
+    simple_macro!(1811);
+    simple_macro!(1812);
+    simple_macro!(1813);
+    simple_macro!(1814);
+    simple_macro!(1815);
+    simple_macro!(1816);
+    simple_macro!(1817);
+    simple_macro!(1818);
+    simple_macro!(1819);
+    simple_macro!(1820);
+    simple_macro!(1821);
+    simple_macro!(1822);
+    simple_macro!(1823);
+    simple_macro!(1824);
+    simple_macro!(1825);
+    simple_macro!(1826);
+    simple_macro!(1827);
+    simple_macro!(1828);
+    simple_macro!(1829);
+    simple_macro!(1830);
+    simple_macro!(1831);
+    simple_macro!(1832);
+    simple_macro!(1833);
+    simple_macro!(1834);
+    simple_macro!(1835);
+    simple_macro!(1836);
+    simple_macro!(1837);
+    simple_macro!(1838);
+    simple_macro!(1839);
+    simple_macro!(1840);
+    simple_macro!(1841);
+    simple_macro!(1842);
+    simple_macro!(1843);
+    simple_macro!(1844);
+    simple_macro!(1845);
+    simple_macro!(1846);
+    simple_macro!(1847);
+    simple_macro!(1848);
+    simple_macro!(1849);
+    simple_macro!(1850);
+    simple_macro!(1851);
+    simple_macro!(1852);
+    simple_macro!(1853);
+    simple_macro!(1854);
+    simple_macro!(1855);
+    simple_macro!(1856);
+    simple_macro!(1857);
+    simple_macro!(1858);
+    simple_macro!(1859);
+    simple_macro!(1860);
+    simple_macro!(1861);
+    simple_macro!(1862);
+    simple_macro!(1863);
+    simple_macro!(1864);
+    simple_macro!(1865);
+    simple_macro!(1866);
+    simple_macro!(1867);
+    simple_macro!(1868);
+    simple_macro!(1869);
+    simple_macro!(1870);
+    simple_macro!(1871);
+    simple_macro!(1872);
+    simple_macro!(1873);
+    simple_macro!(1874);
+    simple_macro!(1875);
+    simple_macro!(1876);
+    simple_macro!(1877);
+    simple_macro!(1878);
+    simple_macro!(1879);
+    simple_macro!(1880);
+    simple_macro!(1881);
+    simple_macro!(1882);
+    simple_macro!(1883);
+    simple_macro!(1884);
+    simple_macro!(1885);
+    simple_macro!(1886);
+    simple_macro!(1887);
+    simple_macro!(1888);
+    simple_macro!(1889);
+    simple_macro!(1890);
+    simple_macro!(1891);
+    simple_macro!(1892);
+    simple_macro!(1893);
+    simple_macro!(1894);
+    simple_macro!(1895);
+    simple_macro!(1896);
+    simple_macro!(1897);
+    simple_macro!(1898);
+    simple_macro!(1899);
+    simple_macro!(1900);
+    simple_macro!(1901);
+    simple_macro!(1902);
+    simple_macro!(1903);
+    simple_macro!(1904);
+    simple_macro!(1905);
+    simple_macro!(1906);
+    simple_macro!(1907);
+    simple_macro!(1908);
+    simple_macro!(1909);
+    simple_macro!(1910);
+    simple_macro!(1911);
+    simple_macro!(1912);
+    simple_macro!(1913);
+    simple_macro!(1914);
+    simple_macro!(1915);
+    simple_macro!(1916);
+    simple_macro!(1917);
+    simple_macro!(1918);
+    simple_macro!(1919);
+    simple_macro!(1920);
+    simple_macro!(1921);
+    simple_macro!(1922);
+    simple_macro!(1923);
+    simple_macro!(1924);
+    simple_macro!(1925);
+    simple_macro!(1926);
+    simple_macro!(1927);
+    simple_macro!(1928);
+    simple_macro!(1929);
+    simple_macro!(1930);
+    simple_macro!(1931);
+    simple_macro!(1932);
+    simple_macro!(1933);
+    simple_macro!(1934);
+    simple_macro!(1935);
+    simple_macro!(1936);
+    simple_macro!(1937);
+    simple_macro!(1938);
+    simple_macro!(1939);
+    simple_macro!(1940);
+    simple_macro!(1941);
+    simple_macro!(1942);
+    simple_macro!(1943);
+    simple_macro!(1944);
+    simple_macro!(1945);
+    simple_macro!(1946);
+    simple_macro!(1947);
+    simple_macro!(1948);
+    simple_macro!(1949);
+    simple_macro!(1950);
+    simple_macro!(1951);
+    simple_macro!(1952);
+    simple_macro!(1953);
+    simple_macro!(1954);
+    simple_macro!(1955);
+    simple_macro!(1956);
+    simple_macro!(1957);
+    simple_macro!(1958);
+    simple_macro!(1959);
+    simple_macro!(1960);
+    simple_macro!(1961);
+    simple_macro!(1962);
+    simple_macro!(1963);
+    simple_macro!(1964);
+    simple_macro!(1965);
+    simple_macro!(1966);
+    simple_macro!(1967);
+    simple_macro!(1968);
+    simple_macro!(1969);
+    simple_macro!(1970);
+    simple_macro!(1971);
+    simple_macro!(1972);
+    simple_macro!(1973);
+    simple_macro!(1974);
+    simple_macro!(1975);
+    simple_macro!(1976);
+    simple_macro!(1977);
+    simple_macro!(1978);
+    simple_macro!(1979);
+    simple_macro!(1980);
+    simple_macro!(1981);
+    simple_macro!(1982);
+    simple_macro!(1983);
+    simple_macro!(1984);
+    simple_macro!(1985);
+    simple_macro!(1986);
+    simple_macro!(1987);
+    simple_macro!(1988);
+    simple_macro!(1989);
+    simple_macro!(1990);
+    simple_macro!(1991);
+    simple_macro!(1992);
+    simple_macro!(1993);
+    simple_macro!(1994);
+    simple_macro!(1995);
+    simple_macro!(1996);
+    simple_macro!(1997);
+    simple_macro!(1998);
+    simple_macro!(1999);
+    simple_macro!(2000);
+    simple_macro!(2001);
+    simple_macro!(2002);
+    simple_macro!(2003);
+    simple_macro!(2004);
+    simple_macro!(2005);
+    simple_macro!(2006);
+    simple_macro!(2007);
+    simple_macro!(2008);
+    simple_macro!(2009);
+    simple_macro!(2010);
+    simple_macro!(2011);
+    simple_macro!(2012);
+    simple_macro!(2013);
+    simple_macro!(2014);
+    simple_macro!(2015);
+    simple_macro!(2016);
+    simple_macro!(2017);
+    simple_macro!(2018);
+    simple_macro!(2019);
+    simple_macro!(2020);
+    simple_macro!(2021);
+    simple_macro!(2022);
+    simple_macro!(2023);
+    simple_macro!(2024);
+    simple_macro!(2025);
+    simple_macro!(2026);
+    simple_macro!(2027);
+    simple_macro!(2028);
+    simple_macro!(2029);
+    simple_macro!(2030);
+    simple_macro!(2031);
+    simple_macro!(2032);
+    simple_macro!(2033);
+    simple_macro!(2034);
+    simple_macro!(2035);
+    simple_macro!(2036);
+    simple_macro!(2037);
+    simple_macro!(2038);
+    simple_macro!(2039);
+    simple_macro!(2040);
+    simple_macro!(2041);
+    simple_macro!(2042);
+    simple_macro!(2043);
+    simple_macro!(2044);
+    simple_macro!(2045);
+    simple_macro!(2046);
+    simple_macro!(2047);
+    simple_macro!(2048);
+    simple_macro!(2049);
+    simple_macro!(2050);
+    simple_macro!(2051);
+    simple_macro!(2052);
+    simple_macro!(2053);
+    simple_macro!(2054);
+    simple_macro!(2055);
+    simple_macro!(2056);
+    simple_macro!(2057);
+    simple_macro!(2058);
+    simple_macro!(2059);
+    simple_macro!(2060);
+    simple_macro!(2061);
+    simple_macro!(2062);
+    simple_macro!(2063);
+    simple_macro!(2064);
+    simple_macro!(2065);
+    simple_macro!(2066);
+    simple_macro!(2067);
+    simple_macro!(2068);
+    simple_macro!(2069);
+    simple_macro!(2070);
+    simple_macro!(2071);
+    simple_macro!(2072);
+    simple_macro!(2073);
+    simple_macro!(2074);
+    simple_macro!(2075);
+    simple_macro!(2076);
+    simple_macro!(2077);
+    simple_macro!(2078);
+    simple_macro!(2079);
+    simple_macro!(2080);
+    simple_macro!(2081);
+    simple_macro!(2082);
+    simple_macro!(2083);
+    simple_macro!(2084);
+    simple_macro!(2085);
+    simple_macro!(2086);
+    simple_macro!(2087);
+    simple_macro!(2088);
+    simple_macro!(2089);
+    simple_macro!(2090);
+    simple_macro!(2091);
+    simple_macro!(2092);
+    simple_macro!(2093);
+    simple_macro!(2094);
+    simple_macro!(2095);
+    simple_macro!(2096);
+    simple_macro!(2097);
+    simple_macro!(2098);
+    simple_macro!(2099);
+    simple_macro!(2100);
+    simple_macro!(2101);
+    simple_macro!(2102);
+    simple_macro!(2103);
+    simple_macro!(2104);
+    simple_macro!(2105);
+    simple_macro!(2106);
+    simple_macro!(2107);
+    simple_macro!(2108);
+    simple_macro!(2109);
+    simple_macro!(2110);
+    simple_macro!(2111);
+    simple_macro!(2112);
+    simple_macro!(2113);
+    simple_macro!(2114);
+    simple_macro!(2115);
+    simple_macro!(2116);
+    simple_macro!(2117);
+    simple_macro!(2118);
+    simple_macro!(2119);
+    simple_macro!(2120);
+    simple_macro!(2121);
+    simple_macro!(2122);
+    simple_macro!(2123);
+    simple_macro!(2124);
+    simple_macro!(2125);
+    simple_macro!(2126);
+    simple_macro!(2127);
+    simple_macro!(2128);
+    simple_macro!(2129);
+    simple_macro!(2130);
+    simple_macro!(2131);
+    simple_macro!(2132);
+    simple_macro!(2133);
+    simple_macro!(2134);
+    simple_macro!(2135);
+    simple_macro!(2136);
+    simple_macro!(2137);
+    simple_macro!(2138);
+    simple_macro!(2139);
+    simple_macro!(2140);
+    simple_macro!(2141);
+    simple_macro!(2142);
+    simple_macro!(2143);
+    simple_macro!(2144);
+    simple_macro!(2145);
+    simple_macro!(2146);
+    simple_macro!(2147);
+    simple_macro!(2148);
+    simple_macro!(2149);
+    simple_macro!(2150);
+    simple_macro!(2151);
+    simple_macro!(2152);
+    simple_macro!(2153);
+    simple_macro!(2154);
+    simple_macro!(2155);
+    simple_macro!(2156);
+    simple_macro!(2157);
+    simple_macro!(2158);
+    simple_macro!(2159);
+    simple_macro!(2160);
+    simple_macro!(2161);
+    simple_macro!(2162);
+    simple_macro!(2163);
+    simple_macro!(2164);
+    simple_macro!(2165);
+    simple_macro!(2166);
+    simple_macro!(2167);
+    simple_macro!(2168);
+    simple_macro!(2169);
+    simple_macro!(2170);
+    simple_macro!(2171);
+    simple_macro!(2172);
+    simple_macro!(2173);
+    simple_macro!(2174);
+    simple_macro!(2175);
+    simple_macro!(2176);
+    simple_macro!(2177);
+    simple_macro!(2178);
+    simple_macro!(2179);
+    simple_macro!(2180);
+    simple_macro!(2181);
+    simple_macro!(2182);
+    simple_macro!(2183);
+    simple_macro!(2184);
+    simple_macro!(2185);
+    simple_macro!(2186);
+    simple_macro!(2187);
+    simple_macro!(2188);
+    simple_macro!(2189);
+    simple_macro!(2190);
+    simple_macro!(2191);
+    simple_macro!(2192);
+    simple_macro!(2193);
+    simple_macro!(2194);
+    simple_macro!(2195);
+    simple_macro!(2196);
+    simple_macro!(2197);
+    simple_macro!(2198);
+    simple_macro!(2199);
+    simple_macro!(2200);
+    simple_macro!(2201);
+    simple_macro!(2202);
+    simple_macro!(2203);
+    simple_macro!(2204);
+    simple_macro!(2205);
+    simple_macro!(2206);
+    simple_macro!(2207);
+    simple_macro!(2208);
+    simple_macro!(2209);
+    simple_macro!(2210);
+    simple_macro!(2211);
+    simple_macro!(2212);
+    simple_macro!(2213);
+    simple_macro!(2214);
+    simple_macro!(2215);
+    simple_macro!(2216);
+    simple_macro!(2217);
+    simple_macro!(2218);
+    simple_macro!(2219);
+    simple_macro!(2220);
+    simple_macro!(2221);
+    simple_macro!(2222);
+    simple_macro!(2223);
+    simple_macro!(2224);
+    simple_macro!(2225);
+    simple_macro!(2226);
+    simple_macro!(2227);
+    simple_macro!(2228);
+    simple_macro!(2229);
+    simple_macro!(2230);
+    simple_macro!(2231);
+    simple_macro!(2232);
+    simple_macro!(2233);
+    simple_macro!(2234);
+    simple_macro!(2235);
+    simple_macro!(2236);
+    simple_macro!(2237);
+    simple_macro!(2238);
+    simple_macro!(2239);
+    simple_macro!(2240);
+    simple_macro!(2241);
+    simple_macro!(2242);
+    simple_macro!(2243);
+    simple_macro!(2244);
+    simple_macro!(2245);
+    simple_macro!(2246);
+    simple_macro!(2247);
+    simple_macro!(2248);
+    simple_macro!(2249);
+    simple_macro!(2250);
+    simple_macro!(2251);
+    simple_macro!(2252);
+    simple_macro!(2253);
+    simple_macro!(2254);
+    simple_macro!(2255);
+    simple_macro!(2256);
+    simple_macro!(2257);
+    simple_macro!(2258);
+    simple_macro!(2259);
+    simple_macro!(2260);
+    simple_macro!(2261);
+    simple_macro!(2262);
+    simple_macro!(2263);
+    simple_macro!(2264);
+    simple_macro!(2265);
+    simple_macro!(2266);
+    simple_macro!(2267);
+    simple_macro!(2268);
+    simple_macro!(2269);
+    simple_macro!(2270);
+    simple_macro!(2271);
+    simple_macro!(2272);
+    simple_macro!(2273);
+    simple_macro!(2274);
+    simple_macro!(2275);
+    simple_macro!(2276);
+    simple_macro!(2277);
+    simple_macro!(2278);
+    simple_macro!(2279);
+    simple_macro!(2280);
+    simple_macro!(2281);
+    simple_macro!(2282);
+    simple_macro!(2283);
+    simple_macro!(2284);
+    simple_macro!(2285);
+    simple_macro!(2286);
+    simple_macro!(2287);
+    simple_macro!(2288);
+    simple_macro!(2289);
+    simple_macro!(2290);
+    simple_macro!(2291);
+    simple_macro!(2292);
+    simple_macro!(2293);
+    simple_macro!(2294);
+    simple_macro!(2295);
+    simple_macro!(2296);
+    simple_macro!(2297);
+    simple_macro!(2298);
+    simple_macro!(2299);
+    simple_macro!(2300);
+    simple_macro!(2301);
+    simple_macro!(2302);
+    simple_macro!(2303);
+    simple_macro!(2304);
+    simple_macro!(2305);
+    simple_macro!(2306);
+    simple_macro!(2307);
+    simple_macro!(2308);
+    simple_macro!(2309);
+    simple_macro!(2310);
+    simple_macro!(2311);
+    simple_macro!(2312);
+    simple_macro!(2313);
+    simple_macro!(2314);
+    simple_macro!(2315);
+    simple_macro!(2316);
+    simple_macro!(2317);
+    simple_macro!(2318);
+    simple_macro!(2319);
+    simple_macro!(2320);
+    simple_macro!(2321);
+    simple_macro!(2322);
+    simple_macro!(2323);
+    simple_macro!(2324);
+    simple_macro!(2325);
+    simple_macro!(2326);
+    simple_macro!(2327);
+    simple_macro!(2328);
+    simple_macro!(2329);
+    simple_macro!(2330);
+    simple_macro!(2331);
+    simple_macro!(2332);
+    simple_macro!(2333);
+    simple_macro!(2334);
+    simple_macro!(2335);
+    simple_macro!(2336);
+    simple_macro!(2337);
+    simple_macro!(2338);
+    simple_macro!(2339);
+    simple_macro!(2340);
+    simple_macro!(2341);
+    simple_macro!(2342);
+    simple_macro!(2343);
+    simple_macro!(2344);
+    simple_macro!(2345);
+    simple_macro!(2346);
+    simple_macro!(2347);
+    simple_macro!(2348);
+    simple_macro!(2349);
+    simple_macro!(2350);
+    simple_macro!(2351);
+    simple_macro!(2352);
+    simple_macro!(2353);
+    simple_macro!(2354);
+    simple_macro!(2355);
+    simple_macro!(2356);
+    simple_macro!(2357);
+    simple_macro!(2358);
+    simple_macro!(2359);
+    simple_macro!(2360);
+    simple_macro!(2361);
+    simple_macro!(2362);
+    simple_macro!(2363);
+    simple_macro!(2364);
+    simple_macro!(2365);
+    simple_macro!(2366);
+    simple_macro!(2367);
+    simple_macro!(2368);
+    simple_macro!(2369);
+    simple_macro!(2370);
+    simple_macro!(2371);
+    simple_macro!(2372);
+    simple_macro!(2373);
+    simple_macro!(2374);
+    simple_macro!(2375);
+    simple_macro!(2376);
+    simple_macro!(2377);
+    simple_macro!(2378);
+    simple_macro!(2379);
+    simple_macro!(2380);
+    simple_macro!(2381);
+    simple_macro!(2382);
+    simple_macro!(2383);
+    simple_macro!(2384);
+    simple_macro!(2385);
+    simple_macro!(2386);
+    simple_macro!(2387);
+    simple_macro!(2388);
+    simple_macro!(2389);
+    simple_macro!(2390);
+    simple_macro!(2391);
+    simple_macro!(2392);
+    simple_macro!(2393);
+    simple_macro!(2394);
+    simple_macro!(2395);
+    simple_macro!(2396);
+    simple_macro!(2397);
+    simple_macro!(2398);
+    simple_macro!(2399);
+    simple_macro!(2400);
+    simple_macro!(2401);
+    simple_macro!(2402);
+    simple_macro!(2403);
+    simple_macro!(2404);
+    simple_macro!(2405);
+    simple_macro!(2406);
+    simple_macro!(2407);
+    simple_macro!(2408);
+    simple_macro!(2409);
+    simple_macro!(2410);
+    simple_macro!(2411);
+    simple_macro!(2412);
+    simple_macro!(2413);
+    simple_macro!(2414);
+    simple_macro!(2415);
+    simple_macro!(2416);
+    simple_macro!(2417);
+    simple_macro!(2418);
+    simple_macro!(2419);
+    simple_macro!(2420);
+    simple_macro!(2421);
+    simple_macro!(2422);
+    simple_macro!(2423);
+    simple_macro!(2424);
+    simple_macro!(2425);
+    simple_macro!(2426);
+    simple_macro!(2427);
+    simple_macro!(2428);
+    simple_macro!(2429);
+    simple_macro!(2430);
+    simple_macro!(2431);
+    simple_macro!(2432);
+    simple_macro!(2433);
+    simple_macro!(2434);
+    simple_macro!(2435);
+    simple_macro!(2436);
+    simple_macro!(2437);
+    simple_macro!(2438);
+    simple_macro!(2439);
+    simple_macro!(2440);
+    simple_macro!(2441);
+    simple_macro!(2442);
+    simple_macro!(2443);
+    simple_macro!(2444);
+    simple_macro!(2445);
+    simple_macro!(2446);
+    simple_macro!(2447);
+    simple_macro!(2448);
+    simple_macro!(2449);
+    simple_macro!(2450);
+    simple_macro!(2451);
+    simple_macro!(2452);
+    simple_macro!(2453);
+    simple_macro!(2454);
+    simple_macro!(2455);
+    simple_macro!(2456);
+    simple_macro!(2457);
+    simple_macro!(2458);
+    simple_macro!(2459);
+    simple_macro!(2460);
+    simple_macro!(2461);
+    simple_macro!(2462);
+    simple_macro!(2463);
+    simple_macro!(2464);
+    simple_macro!(2465);
+    simple_macro!(2466);
+    simple_macro!(2467);
+    simple_macro!(2468);
+    simple_macro!(2469);
+    simple_macro!(2470);
+    simple_macro!(2471);
+    simple_macro!(2472);
+    simple_macro!(2473);
+    simple_macro!(2474);
+    simple_macro!(2475);
+    simple_macro!(2476);
+    simple_macro!(2477);
+    simple_macro!(2478);
+    simple_macro!(2479);
+    simple_macro!(2480);
+    simple_macro!(2481);
+    simple_macro!(2482);
+    simple_macro!(2483);
+    simple_macro!(2484);
+    simple_macro!(2485);
+    simple_macro!(2486);
+    simple_macro!(2487);
+    simple_macro!(2488);
+    simple_macro!(2489);
+    simple_macro!(2490);
+    simple_macro!(2491);
+    simple_macro!(2492);
+    simple_macro!(2493);
+    simple_macro!(2494);
+    simple_macro!(2495);
+    simple_macro!(2496);
+    simple_macro!(2497);
+    simple_macro!(2498);
+    simple_macro!(2499);
+    simple_macro!(2500);
+    simple_macro!(2501);
+    simple_macro!(2502);
+    simple_macro!(2503);
+    simple_macro!(2504);
+    simple_macro!(2505);
+    simple_macro!(2506);
+    simple_macro!(2507);
+    simple_macro!(2508);
+    simple_macro!(2509);
+    simple_macro!(2510);
+    simple_macro!(2511);
+    simple_macro!(2512);
+    simple_macro!(2513);
+    simple_macro!(2514);
+    simple_macro!(2515);
+    simple_macro!(2516);
+    simple_macro!(2517);
+    simple_macro!(2518);
+    simple_macro!(2519);
+    simple_macro!(2520);
+    simple_macro!(2521);
+    simple_macro!(2522);
+    simple_macro!(2523);
+    simple_macro!(2524);
+    simple_macro!(2525);
+    simple_macro!(2526);
+    simple_macro!(2527);
+    simple_macro!(2528);
+    simple_macro!(2529);
+    simple_macro!(2530);
+    simple_macro!(2531);
+    simple_macro!(2532);
+    simple_macro!(2533);
+    simple_macro!(2534);
+    simple_macro!(2535);
+    simple_macro!(2536);
+    simple_macro!(2537);
+    simple_macro!(2538);
+    simple_macro!(2539);
+    simple_macro!(2540);
+    simple_macro!(2541);
+    simple_macro!(2542);
+    simple_macro!(2543);
+    simple_macro!(2544);
+    simple_macro!(2545);
+    simple_macro!(2546);
+    simple_macro!(2547);
+    simple_macro!(2548);
+    simple_macro!(2549);
+    simple_macro!(2550);
+    simple_macro!(2551);
+    simple_macro!(2552);
+    simple_macro!(2553);
+    simple_macro!(2554);
+    simple_macro!(2555);
+    simple_macro!(2556);
+    simple_macro!(2557);
+    simple_macro!(2558);
+    simple_macro!(2559);
+    simple_macro!(2560);
+    simple_macro!(2561);
+    simple_macro!(2562);
+    simple_macro!(2563);
+    simple_macro!(2564);
+    simple_macro!(2565);
+    simple_macro!(2566);
+    simple_macro!(2567);
+    simple_macro!(2568);
+    simple_macro!(2569);
+    simple_macro!(2570);
+    simple_macro!(2571);
+    simple_macro!(2572);
+    simple_macro!(2573);
+    simple_macro!(2574);
+    simple_macro!(2575);
+    simple_macro!(2576);
+    simple_macro!(2577);
+    simple_macro!(2578);
+    simple_macro!(2579);
+    simple_macro!(2580);
+    simple_macro!(2581);
+    simple_macro!(2582);
+    simple_macro!(2583);
+    simple_macro!(2584);
+    simple_macro!(2585);
+    simple_macro!(2586);
+    simple_macro!(2587);
+    simple_macro!(2588);
+    simple_macro!(2589);
+    simple_macro!(2590);
+    simple_macro!(2591);
+    simple_macro!(2592);
+    simple_macro!(2593);
+    simple_macro!(2594);
+    simple_macro!(2595);
+    simple_macro!(2596);
+    simple_macro!(2597);
+    simple_macro!(2598);
+    simple_macro!(2599);
+    simple_macro!(2600);
+    simple_macro!(2601);
+    simple_macro!(2602);
+    simple_macro!(2603);
+    simple_macro!(2604);
+    simple_macro!(2605);
+    simple_macro!(2606);
+    simple_macro!(2607);
+    simple_macro!(2608);
+    simple_macro!(2609);
+    simple_macro!(2610);
+    simple_macro!(2611);
+    simple_macro!(2612);
+    simple_macro!(2613);
+    simple_macro!(2614);
+    simple_macro!(2615);
+    simple_macro!(2616);
+    simple_macro!(2617);
+    simple_macro!(2618);
+    simple_macro!(2619);
+    simple_macro!(2620);
+    simple_macro!(2621);
+    simple_macro!(2622);
+    simple_macro!(2623);
+    simple_macro!(2624);
+    simple_macro!(2625);
+    simple_macro!(2626);
+    simple_macro!(2627);
+    simple_macro!(2628);
+    simple_macro!(2629);
+    simple_macro!(2630);
+    simple_macro!(2631);
+    simple_macro!(2632);
+    simple_macro!(2633);
+    simple_macro!(2634);
+    simple_macro!(2635);
+    simple_macro!(2636);
+    simple_macro!(2637);
+    simple_macro!(2638);
+    simple_macro!(2639);
+    simple_macro!(2640);
+    simple_macro!(2641);
+    simple_macro!(2642);
+    simple_macro!(2643);
+    simple_macro!(2644);
+    simple_macro!(2645);
+    simple_macro!(2646);
+    simple_macro!(2647);
+    simple_macro!(2648);
+    simple_macro!(2649);
+    simple_macro!(2650);
+    simple_macro!(2651);
+    simple_macro!(2652);
+    simple_macro!(2653);
+    simple_macro!(2654);
+    simple_macro!(2655);
+    simple_macro!(2656);
+    simple_macro!(2657);
+    simple_macro!(2658);
+    simple_macro!(2659);
+    simple_macro!(2660);
+    simple_macro!(2661);
+    simple_macro!(2662);
+    simple_macro!(2663);
+    simple_macro!(2664);
+    simple_macro!(2665);
+    simple_macro!(2666);
+    simple_macro!(2667);
+    simple_macro!(2668);
+    simple_macro!(2669);
+    simple_macro!(2670);
+    simple_macro!(2671);
+    simple_macro!(2672);
+    simple_macro!(2673);
+    simple_macro!(2674);
+    simple_macro!(2675);
+    simple_macro!(2676);
+    simple_macro!(2677);
+    simple_macro!(2678);
+    simple_macro!(2679);
+    simple_macro!(2680);
+    simple_macro!(2681);
+    simple_macro!(2682);
+    simple_macro!(2683);
+    simple_macro!(2684);
+    simple_macro!(2685);
+    simple_macro!(2686);
+    simple_macro!(2687);
+    simple_macro!(2688);
+    simple_macro!(2689);
+    simple_macro!(2690);
+    simple_macro!(2691);
+    simple_macro!(2692);
+    simple_macro!(2693);
+    simple_macro!(2694);
+    simple_macro!(2695);
+    simple_macro!(2696);
+    simple_macro!(2697);
+    simple_macro!(2698);
+    simple_macro!(2699);
+    simple_macro!(2700);
+    simple_macro!(2701);
+    simple_macro!(2702);
+    simple_macro!(2703);
+    simple_macro!(2704);
+    simple_macro!(2705);
+    simple_macro!(2706);
+    simple_macro!(2707);
+    simple_macro!(2708);
+    simple_macro!(2709);
+    simple_macro!(2710);
+    simple_macro!(2711);
+    simple_macro!(2712);
+    simple_macro!(2713);
+    simple_macro!(2714);
+    simple_macro!(2715);
+    simple_macro!(2716);
+    simple_macro!(2717);
+    simple_macro!(2718);
+    simple_macro!(2719);
+    simple_macro!(2720);
+    simple_macro!(2721);
+    simple_macro!(2722);
+    simple_macro!(2723);
+    simple_macro!(2724);
+    simple_macro!(2725);
+    simple_macro!(2726);
+    simple_macro!(2727);
+    simple_macro!(2728);
+    simple_macro!(2729);
+    simple_macro!(2730);
+    simple_macro!(2731);
+    simple_macro!(2732);
+    simple_macro!(2733);
+    simple_macro!(2734);
+    simple_macro!(2735);
+    simple_macro!(2736);
+    simple_macro!(2737);
+    simple_macro!(2738);
+    simple_macro!(2739);
+    simple_macro!(2740);
+    simple_macro!(2741);
+    simple_macro!(2742);
+    simple_macro!(2743);
+    simple_macro!(2744);
+    simple_macro!(2745);
+    simple_macro!(2746);
+    simple_macro!(2747);
+    simple_macro!(2748);
+    simple_macro!(2749);
+    simple_macro!(2750);
+    simple_macro!(2751);
+    simple_macro!(2752);
+    simple_macro!(2753);
+    simple_macro!(2754);
+    simple_macro!(2755);
+    simple_macro!(2756);
+    simple_macro!(2757);
+    simple_macro!(2758);
+    simple_macro!(2759);
+    simple_macro!(2760);
+    simple_macro!(2761);
+    simple_macro!(2762);
+    simple_macro!(2763);
+    simple_macro!(2764);
+    simple_macro!(2765);
+    simple_macro!(2766);
+    simple_macro!(2767);
+    simple_macro!(2768);
+    simple_macro!(2769);
+    simple_macro!(2770);
+    simple_macro!(2771);
+    simple_macro!(2772);
+    simple_macro!(2773);
+    simple_macro!(2774);
+    simple_macro!(2775);
+    simple_macro!(2776);
+    simple_macro!(2777);
+    simple_macro!(2778);
+    simple_macro!(2779);
+    simple_macro!(2780);
+    simple_macro!(2781);
+    simple_macro!(2782);
+    simple_macro!(2783);
+    simple_macro!(2784);
+    simple_macro!(2785);
+    simple_macro!(2786);
+    simple_macro!(2787);
+    simple_macro!(2788);
+    simple_macro!(2789);
+    simple_macro!(2790);
+    simple_macro!(2791);
+    simple_macro!(2792);
+    simple_macro!(2793);
+    simple_macro!(2794);
+    simple_macro!(2795);
+    simple_macro!(2796);
+    simple_macro!(2797);
+    simple_macro!(2798);
+    simple_macro!(2799);
+    simple_macro!(2800);
+    simple_macro!(2801);
+    simple_macro!(2802);
+    simple_macro!(2803);
+    simple_macro!(2804);
+    simple_macro!(2805);
+    simple_macro!(2806);
+    simple_macro!(2807);
+    simple_macro!(2808);
+    simple_macro!(2809);
+    simple_macro!(2810);
+    simple_macro!(2811);
+    simple_macro!(2812);
+    simple_macro!(2813);
+    simple_macro!(2814);
+    simple_macro!(2815);
+    simple_macro!(2816);
+    simple_macro!(2817);
+    simple_macro!(2818);
+    simple_macro!(2819);
+    simple_macro!(2820);
+    simple_macro!(2821);
+    simple_macro!(2822);
+    simple_macro!(2823);
+    simple_macro!(2824);
+    simple_macro!(2825);
+    simple_macro!(2826);
+    simple_macro!(2827);
+    simple_macro!(2828);
+    simple_macro!(2829);
+    simple_macro!(2830);
+    simple_macro!(2831);
+    simple_macro!(2832);
+    simple_macro!(2833);
+    simple_macro!(2834);
+    simple_macro!(2835);
+    simple_macro!(2836);
+    simple_macro!(2837);
+    simple_macro!(2838);
+    simple_macro!(2839);
+    simple_macro!(2840);
+    simple_macro!(2841);
+    simple_macro!(2842);
+    simple_macro!(2843);
+    simple_macro!(2844);
+    simple_macro!(2845);
+    simple_macro!(2846);
+    simple_macro!(2847);
+    simple_macro!(2848);
+    simple_macro!(2849);
+    simple_macro!(2850);
+    simple_macro!(2851);
+    simple_macro!(2852);
+    simple_macro!(2853);
+    simple_macro!(2854);
+    simple_macro!(2855);
+    simple_macro!(2856);
+    simple_macro!(2857);
+    simple_macro!(2858);
+    simple_macro!(2859);
+    simple_macro!(2860);
+    simple_macro!(2861);
+    simple_macro!(2862);
+    simple_macro!(2863);
+    simple_macro!(2864);
+    simple_macro!(2865);
+    simple_macro!(2866);
+    simple_macro!(2867);
+    simple_macro!(2868);
+    simple_macro!(2869);
+    simple_macro!(2870);
+    simple_macro!(2871);
+    simple_macro!(2872);
+    simple_macro!(2873);
+    simple_macro!(2874);
+    simple_macro!(2875);
+    simple_macro!(2876);
+    simple_macro!(2877);
+    simple_macro!(2878);
+    simple_macro!(2879);
+    simple_macro!(2880);
+    simple_macro!(2881);
+    simple_macro!(2882);
+    simple_macro!(2883);
+    simple_macro!(2884);
+    simple_macro!(2885);
+    simple_macro!(2886);
+    simple_macro!(2887);
+    simple_macro!(2888);
+    simple_macro!(2889);
+    simple_macro!(2890);
+    simple_macro!(2891);
+    simple_macro!(2892);
+    simple_macro!(2893);
+    simple_macro!(2894);
+    simple_macro!(2895);
+    simple_macro!(2896);
+    simple_macro!(2897);
+    simple_macro!(2898);
+    simple_macro!(2899);
+    simple_macro!(2900);
+    simple_macro!(2901);
+    simple_macro!(2902);
+    simple_macro!(2903);
+    simple_macro!(2904);
+    simple_macro!(2905);
+    simple_macro!(2906);
+    simple_macro!(2907);
+    simple_macro!(2908);
+    simple_macro!(2909);
+    simple_macro!(2910);
+    simple_macro!(2911);
+    simple_macro!(2912);
+    simple_macro!(2913);
+    simple_macro!(2914);
+    simple_macro!(2915);
+    simple_macro!(2916);
+    simple_macro!(2917);
+    simple_macro!(2918);
+    simple_macro!(2919);
+    simple_macro!(2920);
+    simple_macro!(2921);
+    simple_macro!(2922);
+    simple_macro!(2923);
+    simple_macro!(2924);
+    simple_macro!(2925);
+    simple_macro!(2926);
+    simple_macro!(2927);
+    simple_macro!(2928);
+    simple_macro!(2929);
+    simple_macro!(2930);
+    simple_macro!(2931);
+    simple_macro!(2932);
+    simple_macro!(2933);
+    simple_macro!(2934);
+    simple_macro!(2935);
+    simple_macro!(2936);
+    simple_macro!(2937);
+    simple_macro!(2938);
+    simple_macro!(2939);
+    simple_macro!(2940);
+    simple_macro!(2941);
+    simple_macro!(2942);
+    simple_macro!(2943);
+    simple_macro!(2944);
+    simple_macro!(2945);
+    simple_macro!(2946);
+    simple_macro!(2947);
+    simple_macro!(2948);
+    simple_macro!(2949);
+    simple_macro!(2950);
+    simple_macro!(2951);
+    simple_macro!(2952);
+    simple_macro!(2953);
+    simple_macro!(2954);
+    simple_macro!(2955);
+    simple_macro!(2956);
+    simple_macro!(2957);
+    simple_macro!(2958);
+    simple_macro!(2959);
+    simple_macro!(2960);
+    simple_macro!(2961);
+    simple_macro!(2962);
+    simple_macro!(2963);
+    simple_macro!(2964);
+    simple_macro!(2965);
+    simple_macro!(2966);
+    simple_macro!(2967);
+    simple_macro!(2968);
+    simple_macro!(2969);
+    simple_macro!(2970);
+    simple_macro!(2971);
+    simple_macro!(2972);
+    simple_macro!(2973);
+    simple_macro!(2974);
+    simple_macro!(2975);
+    simple_macro!(2976);
+    simple_macro!(2977);
+    simple_macro!(2978);
+    simple_macro!(2979);
+    simple_macro!(2980);
+    simple_macro!(2981);
+    simple_macro!(2982);
+    simple_macro!(2983);
+    simple_macro!(2984);
+    simple_macro!(2985);
+    simple_macro!(2986);
+    simple_macro!(2987);
+    simple_macro!(2988);
+    simple_macro!(2989);
+    simple_macro!(2990);
+    simple_macro!(2991);
+    simple_macro!(2992);
+    simple_macro!(2993);
+    simple_macro!(2994);
+    simple_macro!(2995);
+    simple_macro!(2996);
+    simple_macro!(2997);
+    simple_macro!(2998);
+    simple_macro!(2999);
+    simple_macro!(3000);
+    simple_macro!(3001);
+    simple_macro!(3002);
+    simple_macro!(3003);
+    simple_macro!(3004);
+    simple_macro!(3005);
+    simple_macro!(3006);
+    simple_macro!(3007);
+    simple_macro!(3008);
+    simple_macro!(3009);
+    simple_macro!(3010);
+    simple_macro!(3011);
+    simple_macro!(3012);
+    simple_macro!(3013);
+    simple_macro!(3014);
+    simple_macro!(3015);
+    simple_macro!(3016);
+    simple_macro!(3017);
+    simple_macro!(3018);
+    simple_macro!(3019);
+    simple_macro!(3020);
+    simple_macro!(3021);
+    simple_macro!(3022);
+    simple_macro!(3023);
+    simple_macro!(3024);
+    simple_macro!(3025);
+    simple_macro!(3026);
+    simple_macro!(3027);
+    simple_macro!(3028);
+    simple_macro!(3029);
+    simple_macro!(3030);
+    simple_macro!(3031);
+    simple_macro!(3032);
+    simple_macro!(3033);
+    simple_macro!(3034);
+    simple_macro!(3035);
+    simple_macro!(3036);
+    simple_macro!(3037);
+    simple_macro!(3038);
+    simple_macro!(3039);
+    simple_macro!(3040);
+    simple_macro!(3041);
+    simple_macro!(3042);
+    simple_macro!(3043);
+    simple_macro!(3044);
+    simple_macro!(3045);
+    simple_macro!(3046);
+    simple_macro!(3047);
+    simple_macro!(3048);
+    simple_macro!(3049);
+    simple_macro!(3050);
+    simple_macro!(3051);
+    simple_macro!(3052);
+    simple_macro!(3053);
+    simple_macro!(3054);
+    simple_macro!(3055);
+    simple_macro!(3056);
+    simple_macro!(3057);
+    simple_macro!(3058);
+    simple_macro!(3059);
+    simple_macro!(3060);
+    simple_macro!(3061);
+    simple_macro!(3062);
+    simple_macro!(3063);
+    simple_macro!(3064);
+    simple_macro!(3065);
+    simple_macro!(3066);
+    simple_macro!(3067);
+    simple_macro!(3068);
+    simple_macro!(3069);
+    simple_macro!(3070);
+    simple_macro!(3071);
+    simple_macro!(3072);
+    simple_macro!(3073);
+    simple_macro!(3074);
+    simple_macro!(3075);
+    simple_macro!(3076);
+    simple_macro!(3077);
+    simple_macro!(3078);
+    simple_macro!(3079);
+    simple_macro!(3080);
+    simple_macro!(3081);
+    simple_macro!(3082);
+    simple_macro!(3083);
+    simple_macro!(3084);
+    simple_macro!(3085);
+    simple_macro!(3086);
+    simple_macro!(3087);
+    simple_macro!(3088);
+    simple_macro!(3089);
+    simple_macro!(3090);
+    simple_macro!(3091);
+    simple_macro!(3092);
+    simple_macro!(3093);
+    simple_macro!(3094);
+    simple_macro!(3095);
+    simple_macro!(3096);
+    simple_macro!(3097);
+    simple_macro!(3098);
+    simple_macro!(3099);
+    simple_macro!(3100);
+    simple_macro!(3101);
+    simple_macro!(3102);
+    simple_macro!(3103);
+    simple_macro!(3104);
+    simple_macro!(3105);
+    simple_macro!(3106);
+    simple_macro!(3107);
+    simple_macro!(3108);
+    simple_macro!(3109);
+    simple_macro!(3110);
+    simple_macro!(3111);
+    simple_macro!(3112);
+    simple_macro!(3113);
+    simple_macro!(3114);
+    simple_macro!(3115);
+    simple_macro!(3116);
+    simple_macro!(3117);
+    simple_macro!(3118);
+    simple_macro!(3119);
+    simple_macro!(3120);
+    simple_macro!(3121);
+    simple_macro!(3122);
+    simple_macro!(3123);
+    simple_macro!(3124);
+    simple_macro!(3125);
+    simple_macro!(3126);
+    simple_macro!(3127);
+    simple_macro!(3128);
+    simple_macro!(3129);
+    simple_macro!(3130);
+    simple_macro!(3131);
+    simple_macro!(3132);
+    simple_macro!(3133);
+    simple_macro!(3134);
+    simple_macro!(3135);
+    simple_macro!(3136);
+    simple_macro!(3137);
+    simple_macro!(3138);
+    simple_macro!(3139);
+    simple_macro!(3140);
+    simple_macro!(3141);
+    simple_macro!(3142);
+    simple_macro!(3143);
+    simple_macro!(3144);
+    simple_macro!(3145);
+    simple_macro!(3146);
+    simple_macro!(3147);
+    simple_macro!(3148);
+    simple_macro!(3149);
+    simple_macro!(3150);
+    simple_macro!(3151);
+    simple_macro!(3152);
+    simple_macro!(3153);
+    simple_macro!(3154);
+    simple_macro!(3155);
+    simple_macro!(3156);
+    simple_macro!(3157);
+    simple_macro!(3158);
+    simple_macro!(3159);
+    simple_macro!(3160);
+    simple_macro!(3161);
+    simple_macro!(3162);
+    simple_macro!(3163);
+    simple_macro!(3164);
+    simple_macro!(3165);
+    simple_macro!(3166);
+    simple_macro!(3167);
+    simple_macro!(3168);
+    simple_macro!(3169);
+    simple_macro!(3170);
+    simple_macro!(3171);
+    simple_macro!(3172);
+    simple_macro!(3173);
+    simple_macro!(3174);
+    simple_macro!(3175);
+    simple_macro!(3176);
+    simple_macro!(3177);
+    simple_macro!(3178);
+    simple_macro!(3179);
+    simple_macro!(3180);
+    simple_macro!(3181);
+    simple_macro!(3182);
+    simple_macro!(3183);
+    simple_macro!(3184);
+    simple_macro!(3185);
+    simple_macro!(3186);
+    simple_macro!(3187);
+    simple_macro!(3188);
+    simple_macro!(3189);
+    simple_macro!(3190);
+    simple_macro!(3191);
+    simple_macro!(3192);
+    simple_macro!(3193);
+    simple_macro!(3194);
+    simple_macro!(3195);
+    simple_macro!(3196);
+    simple_macro!(3197);
+    simple_macro!(3198);
+    simple_macro!(3199);
+    simple_macro!(3200);
+    simple_macro!(3201);
+    simple_macro!(3202);
+    simple_macro!(3203);
+    simple_macro!(3204);
+    simple_macro!(3205);
+    simple_macro!(3206);
+    simple_macro!(3207);
+    simple_macro!(3208);
+    simple_macro!(3209);
+    simple_macro!(3210);
+    simple_macro!(3211);
+    simple_macro!(3212);
+    simple_macro!(3213);
+    simple_macro!(3214);
+    simple_macro!(3215);
+    simple_macro!(3216);
+    simple_macro!(3217);
+    simple_macro!(3218);
+    simple_macro!(3219);
+    simple_macro!(3220);
+    simple_macro!(3221);
+    simple_macro!(3222);
+    simple_macro!(3223);
+    simple_macro!(3224);
+    simple_macro!(3225);
+    simple_macro!(3226);
+    simple_macro!(3227);
+    simple_macro!(3228);
+    simple_macro!(3229);
+    simple_macro!(3230);
+    simple_macro!(3231);
+    simple_macro!(3232);
+    simple_macro!(3233);
+    simple_macro!(3234);
+    simple_macro!(3235);
+    simple_macro!(3236);
+    simple_macro!(3237);
+    simple_macro!(3238);
+    simple_macro!(3239);
+    simple_macro!(3240);
+    simple_macro!(3241);
+    simple_macro!(3242);
+    simple_macro!(3243);
+    simple_macro!(3244);
+    simple_macro!(3245);
+    simple_macro!(3246);
+    simple_macro!(3247);
+    simple_macro!(3248);
+    simple_macro!(3249);
+    simple_macro!(3250);
+    simple_macro!(3251);
+    simple_macro!(3252);
+    simple_macro!(3253);
+    simple_macro!(3254);
+    simple_macro!(3255);
+    simple_macro!(3256);
+    simple_macro!(3257);
+    simple_macro!(3258);
+    simple_macro!(3259);
+    simple_macro!(3260);
+    simple_macro!(3261);
+    simple_macro!(3262);
+    simple_macro!(3263);
+    simple_macro!(3264);
+    simple_macro!(3265);
+    simple_macro!(3266);
+    simple_macro!(3267);
+    simple_macro!(3268);
+    simple_macro!(3269);
+    simple_macro!(3270);
+    simple_macro!(3271);
+    simple_macro!(3272);
+    simple_macro!(3273);
+    simple_macro!(3274);
+    simple_macro!(3275);
+    simple_macro!(3276);
+    simple_macro!(3277);
+    simple_macro!(3278);
+    simple_macro!(3279);
+    simple_macro!(3280);
+    simple_macro!(3281);
+    simple_macro!(3282);
+    simple_macro!(3283);
+    simple_macro!(3284);
+    simple_macro!(3285);
+    simple_macro!(3286);
+    simple_macro!(3287);
+    simple_macro!(3288);
+    simple_macro!(3289);
+    simple_macro!(3290);
+    simple_macro!(3291);
+    simple_macro!(3292);
+    simple_macro!(3293);
+    simple_macro!(3294);
+    simple_macro!(3295);
+    simple_macro!(3296);
+    simple_macro!(3297);
+    simple_macro!(3298);
+    simple_macro!(3299);
+    simple_macro!(3300);
+    simple_macro!(3301);
+    simple_macro!(3302);
+    simple_macro!(3303);
+    simple_macro!(3304);
+    simple_macro!(3305);
+    simple_macro!(3306);
+    simple_macro!(3307);
+    simple_macro!(3308);
+    simple_macro!(3309);
+    simple_macro!(3310);
+    simple_macro!(3311);
+    simple_macro!(3312);
+    simple_macro!(3313);
+    simple_macro!(3314);
+    simple_macro!(3315);
+    simple_macro!(3316);
+    simple_macro!(3317);
+    simple_macro!(3318);
+    simple_macro!(3319);
+    simple_macro!(3320);
+    simple_macro!(3321);
+    simple_macro!(3322);
+    simple_macro!(3323);
+    simple_macro!(3324);
+    simple_macro!(3325);
+    simple_macro!(3326);
+    simple_macro!(3327);
+    simple_macro!(3328);
+    simple_macro!(3329);
+    simple_macro!(3330);
+    simple_macro!(3331);
+    simple_macro!(3332);
+    simple_macro!(3333);
+    simple_macro!(3334);
+    simple_macro!(3335);
+    simple_macro!(3336);
+    simple_macro!(3337);
+    simple_macro!(3338);
+    simple_macro!(3339);
+    simple_macro!(3340);
+    simple_macro!(3341);
+    simple_macro!(3342);
+    simple_macro!(3343);
+    simple_macro!(3344);
+    simple_macro!(3345);
+    simple_macro!(3346);
+    simple_macro!(3347);
+    simple_macro!(3348);
+    simple_macro!(3349);
+    simple_macro!(3350);
+    simple_macro!(3351);
+    simple_macro!(3352);
+    simple_macro!(3353);
+    simple_macro!(3354);
+    simple_macro!(3355);
+    simple_macro!(3356);
+    simple_macro!(3357);
+    simple_macro!(3358);
+    simple_macro!(3359);
+    simple_macro!(3360);
+    simple_macro!(3361);
+    simple_macro!(3362);
+    simple_macro!(3363);
+    simple_macro!(3364);
+    simple_macro!(3365);
+    simple_macro!(3366);
+    simple_macro!(3367);
+    simple_macro!(3368);
+    simple_macro!(3369);
+    simple_macro!(3370);
+    simple_macro!(3371);
+    simple_macro!(3372);
+    simple_macro!(3373);
+    simple_macro!(3374);
+    simple_macro!(3375);
+    simple_macro!(3376);
+    simple_macro!(3377);
+    simple_macro!(3378);
+    simple_macro!(3379);
+    simple_macro!(3380);
+    simple_macro!(3381);
+    simple_macro!(3382);
+    simple_macro!(3383);
+    simple_macro!(3384);
+    simple_macro!(3385);
+    simple_macro!(3386);
+    simple_macro!(3387);
+    simple_macro!(3388);
+    simple_macro!(3389);
+    simple_macro!(3390);
+    simple_macro!(3391);
+    simple_macro!(3392);
+    simple_macro!(3393);
+    simple_macro!(3394);
+    simple_macro!(3395);
+    simple_macro!(3396);
+    simple_macro!(3397);
+    simple_macro!(3398);
+    simple_macro!(3399);
+    simple_macro!(3400);
+    simple_macro!(3401);
+    simple_macro!(3402);
+    simple_macro!(3403);
+    simple_macro!(3404);
+    simple_macro!(3405);
+    simple_macro!(3406);
+    simple_macro!(3407);
+    simple_macro!(3408);
+    simple_macro!(3409);
+    simple_macro!(3410);
+    simple_macro!(3411);
+    simple_macro!(3412);
+    simple_macro!(3413);
+    simple_macro!(3414);
+    simple_macro!(3415);
+    simple_macro!(3416);
+    simple_macro!(3417);
+    simple_macro!(3418);
+    simple_macro!(3419);
+    simple_macro!(3420);
+    simple_macro!(3421);
+    simple_macro!(3422);
+    simple_macro!(3423);
+    simple_macro!(3424);
+    simple_macro!(3425);
+    simple_macro!(3426);
+    simple_macro!(3427);
+    simple_macro!(3428);
+    simple_macro!(3429);
+    simple_macro!(3430);
+    simple_macro!(3431);
+    simple_macro!(3432);
+    simple_macro!(3433);
+    simple_macro!(3434);
+    simple_macro!(3435);
+    simple_macro!(3436);
+    simple_macro!(3437);
+    simple_macro!(3438);
+    simple_macro!(3439);
+    simple_macro!(3440);
+    simple_macro!(3441);
+    simple_macro!(3442);
+    simple_macro!(3443);
+    simple_macro!(3444);
+    simple_macro!(3445);
+    simple_macro!(3446);
+    simple_macro!(3447);
+    simple_macro!(3448);
+    simple_macro!(3449);
+    simple_macro!(3450);
+    simple_macro!(3451);
+    simple_macro!(3452);
+    simple_macro!(3453);
+    simple_macro!(3454);
+    simple_macro!(3455);
+    simple_macro!(3456);
+    simple_macro!(3457);
+    simple_macro!(3458);
+    simple_macro!(3459);
+    simple_macro!(3460);
+    simple_macro!(3461);
+    simple_macro!(3462);
+    simple_macro!(3463);
+    simple_macro!(3464);
+    simple_macro!(3465);
+    simple_macro!(3466);
+    simple_macro!(3467);
+    simple_macro!(3468);
+    simple_macro!(3469);
+    simple_macro!(3470);
+    simple_macro!(3471);
+    simple_macro!(3472);
+    simple_macro!(3473);
+    simple_macro!(3474);
+    simple_macro!(3475);
+    simple_macro!(3476);
+    simple_macro!(3477);
+    simple_macro!(3478);
+    simple_macro!(3479);
+    simple_macro!(3480);
+    simple_macro!(3481);
+    simple_macro!(3482);
+    simple_macro!(3483);
+    simple_macro!(3484);
+    simple_macro!(3485);
+    simple_macro!(3486);
+    simple_macro!(3487);
+    simple_macro!(3488);
+    simple_macro!(3489);
+    simple_macro!(3490);
+    simple_macro!(3491);
+    simple_macro!(3492);
+    simple_macro!(3493);
+    simple_macro!(3494);
+    simple_macro!(3495);
+    simple_macro!(3496);
+    simple_macro!(3497);
+    simple_macro!(3498);
+    simple_macro!(3499);
+    simple_macro!(3500);
+    simple_macro!(3501);
+    simple_macro!(3502);
+    simple_macro!(3503);
+    simple_macro!(3504);
+    simple_macro!(3505);
+    simple_macro!(3506);
+    simple_macro!(3507);
+    simple_macro!(3508);
+    simple_macro!(3509);
+    simple_macro!(3510);
+    simple_macro!(3511);
+    simple_macro!(3512);
+    simple_macro!(3513);
+    simple_macro!(3514);
+    simple_macro!(3515);
+    simple_macro!(3516);
+    simple_macro!(3517);
+    simple_macro!(3518);
+    simple_macro!(3519);
+    simple_macro!(3520);
+    simple_macro!(3521);
+    simple_macro!(3522);
+    simple_macro!(3523);
+    simple_macro!(3524);
+    simple_macro!(3525);
+    simple_macro!(3526);
+    simple_macro!(3527);
+    simple_macro!(3528);
+    simple_macro!(3529);
+    simple_macro!(3530);
+    simple_macro!(3531);
+    simple_macro!(3532);
+    simple_macro!(3533);
+    simple_macro!(3534);
+    simple_macro!(3535);
+    simple_macro!(3536);
+    simple_macro!(3537);
+    simple_macro!(3538);
+    simple_macro!(3539);
+    simple_macro!(3540);
+    simple_macro!(3541);
+    simple_macro!(3542);
+    simple_macro!(3543);
+    simple_macro!(3544);
+    simple_macro!(3545);
+    simple_macro!(3546);
+    simple_macro!(3547);
+    simple_macro!(3548);
+    simple_macro!(3549);
+    simple_macro!(3550);
+    simple_macro!(3551);
+    simple_macro!(3552);
+    simple_macro!(3553);
+    simple_macro!(3554);
+    simple_macro!(3555);
+    simple_macro!(3556);
+    simple_macro!(3557);
+    simple_macro!(3558);
+    simple_macro!(3559);
+    simple_macro!(3560);
+    simple_macro!(3561);
+    simple_macro!(3562);
+    simple_macro!(3563);
+    simple_macro!(3564);
+    simple_macro!(3565);
+    simple_macro!(3566);
+    simple_macro!(3567);
+    simple_macro!(3568);
+    simple_macro!(3569);
+    simple_macro!(3570);
+    simple_macro!(3571);
+    simple_macro!(3572);
+    simple_macro!(3573);
+    simple_macro!(3574);
+    simple_macro!(3575);
+    simple_macro!(3576);
+    simple_macro!(3577);
+    simple_macro!(3578);
+    simple_macro!(3579);
+    simple_macro!(3580);
+    simple_macro!(3581);
+    simple_macro!(3582);
+    simple_macro!(3583);
+    simple_macro!(3584);
+    simple_macro!(3585);
+    simple_macro!(3586);
+    simple_macro!(3587);
+    simple_macro!(3588);
+    simple_macro!(3589);
+    simple_macro!(3590);
+    simple_macro!(3591);
+    simple_macro!(3592);
+    simple_macro!(3593);
+    simple_macro!(3594);
+    simple_macro!(3595);
+    simple_macro!(3596);
+    simple_macro!(3597);
+    simple_macro!(3598);
+    simple_macro!(3599);
+    simple_macro!(3600);
+    simple_macro!(3601);
+    simple_macro!(3602);
+    simple_macro!(3603);
+    simple_macro!(3604);
+    simple_macro!(3605);
+    simple_macro!(3606);
+    simple_macro!(3607);
+    simple_macro!(3608);
+    simple_macro!(3609);
+    simple_macro!(3610);
+    simple_macro!(3611);
+    simple_macro!(3612);
+    simple_macro!(3613);
+    simple_macro!(3614);
+    simple_macro!(3615);
+    simple_macro!(3616);
+    simple_macro!(3617);
+    simple_macro!(3618);
+    simple_macro!(3619);
+    simple_macro!(3620);
+    simple_macro!(3621);
+    simple_macro!(3622);
+    simple_macro!(3623);
+    simple_macro!(3624);
+    simple_macro!(3625);
+    simple_macro!(3626);
+    simple_macro!(3627);
+    simple_macro!(3628);
+    simple_macro!(3629);
+    simple_macro!(3630);
+    simple_macro!(3631);
+    simple_macro!(3632);
+    simple_macro!(3633);
+    simple_macro!(3634);
+    simple_macro!(3635);
+    simple_macro!(3636);
+    simple_macro!(3637);
+    simple_macro!(3638);
+    simple_macro!(3639);
+    simple_macro!(3640);
+    simple_macro!(3641);
+    simple_macro!(3642);
+    simple_macro!(3643);
+    simple_macro!(3644);
+    simple_macro!(3645);
+    simple_macro!(3646);
+    simple_macro!(3647);
+    simple_macro!(3648);
+    simple_macro!(3649);
+    simple_macro!(3650);
+    simple_macro!(3651);
+    simple_macro!(3652);
+    simple_macro!(3653);
+    simple_macro!(3654);
+    simple_macro!(3655);
+    simple_macro!(3656);
+    simple_macro!(3657);
+    simple_macro!(3658);
+    simple_macro!(3659);
+    simple_macro!(3660);
+    simple_macro!(3661);
+    simple_macro!(3662);
+    simple_macro!(3663);
+    simple_macro!(3664);
+    simple_macro!(3665);
+    simple_macro!(3666);
+    simple_macro!(3667);
+    simple_macro!(3668);
+    simple_macro!(3669);
+    simple_macro!(3670);
+    simple_macro!(3671);
+    simple_macro!(3672);
+    simple_macro!(3673);
+    simple_macro!(3674);
+    simple_macro!(3675);
+    simple_macro!(3676);
+    simple_macro!(3677);
+    simple_macro!(3678);
+    simple_macro!(3679);
+    simple_macro!(3680);
+    simple_macro!(3681);
+    simple_macro!(3682);
+    simple_macro!(3683);
+    simple_macro!(3684);
+    simple_macro!(3685);
+    simple_macro!(3686);
+    simple_macro!(3687);
+    simple_macro!(3688);
+    simple_macro!(3689);
+    simple_macro!(3690);
+    simple_macro!(3691);
+    simple_macro!(3692);
+    simple_macro!(3693);
+    simple_macro!(3694);
+    simple_macro!(3695);
+    simple_macro!(3696);
+    simple_macro!(3697);
+    simple_macro!(3698);
+    simple_macro!(3699);
+    simple_macro!(3700);
+    simple_macro!(3701);
+    simple_macro!(3702);
+    simple_macro!(3703);
+    simple_macro!(3704);
+    simple_macro!(3705);
+    simple_macro!(3706);
+    simple_macro!(3707);
+    simple_macro!(3708);
+    simple_macro!(3709);
+    simple_macro!(3710);
+    simple_macro!(3711);
+    simple_macro!(3712);
+    simple_macro!(3713);
+    simple_macro!(3714);
+    simple_macro!(3715);
+    simple_macro!(3716);
+    simple_macro!(3717);
+    simple_macro!(3718);
+    simple_macro!(3719);
+    simple_macro!(3720);
+    simple_macro!(3721);
+    simple_macro!(3722);
+    simple_macro!(3723);
+    simple_macro!(3724);
+    simple_macro!(3725);
+    simple_macro!(3726);
+    simple_macro!(3727);
+    simple_macro!(3728);
+    simple_macro!(3729);
+    simple_macro!(3730);
+    simple_macro!(3731);
+    simple_macro!(3732);
+    simple_macro!(3733);
+    simple_macro!(3734);
+    simple_macro!(3735);
+    simple_macro!(3736);
+    simple_macro!(3737);
+    simple_macro!(3738);
+    simple_macro!(3739);
+    simple_macro!(3740);
+    simple_macro!(3741);
+    simple_macro!(3742);
+    simple_macro!(3743);
+    simple_macro!(3744);
+    simple_macro!(3745);
+    simple_macro!(3746);
+    simple_macro!(3747);
+    simple_macro!(3748);
+    simple_macro!(3749);
+    simple_macro!(3750);
+    simple_macro!(3751);
+    simple_macro!(3752);
+    simple_macro!(3753);
+    simple_macro!(3754);
+    simple_macro!(3755);
+    simple_macro!(3756);
+    simple_macro!(3757);
+    simple_macro!(3758);
+    simple_macro!(3759);
+    simple_macro!(3760);
+    simple_macro!(3761);
+    simple_macro!(3762);
+    simple_macro!(3763);
+    simple_macro!(3764);
+    simple_macro!(3765);
+    simple_macro!(3766);
+    simple_macro!(3767);
+    simple_macro!(3768);
+    simple_macro!(3769);
+    simple_macro!(3770);
+    simple_macro!(3771);
+    simple_macro!(3772);
+    simple_macro!(3773);
+    simple_macro!(3774);
+    simple_macro!(3775);
+    simple_macro!(3776);
+    simple_macro!(3777);
+    simple_macro!(3778);
+    simple_macro!(3779);
+    simple_macro!(3780);
+    simple_macro!(3781);
+    simple_macro!(3782);
+    simple_macro!(3783);
+    simple_macro!(3784);
+    simple_macro!(3785);
+    simple_macro!(3786);
+    simple_macro!(3787);
+    simple_macro!(3788);
+    simple_macro!(3789);
+    simple_macro!(3790);
+    simple_macro!(3791);
+    simple_macro!(3792);
+    simple_macro!(3793);
+    simple_macro!(3794);
+    simple_macro!(3795);
+    simple_macro!(3796);
+    simple_macro!(3797);
+    simple_macro!(3798);
+    simple_macro!(3799);
+    simple_macro!(3800);
+    simple_macro!(3801);
+    simple_macro!(3802);
+    simple_macro!(3803);
+    simple_macro!(3804);
+    simple_macro!(3805);
+    simple_macro!(3806);
+    simple_macro!(3807);
+    simple_macro!(3808);
+    simple_macro!(3809);
+    simple_macro!(3810);
+    simple_macro!(3811);
+    simple_macro!(3812);
+    simple_macro!(3813);
+    simple_macro!(3814);
+    simple_macro!(3815);
+    simple_macro!(3816);
+    simple_macro!(3817);
+    simple_macro!(3818);
+    simple_macro!(3819);
+    simple_macro!(3820);
+    simple_macro!(3821);
+    simple_macro!(3822);
+    simple_macro!(3823);
+    simple_macro!(3824);
+    simple_macro!(3825);
+    simple_macro!(3826);
+    simple_macro!(3827);
+    simple_macro!(3828);
+    simple_macro!(3829);
+    simple_macro!(3830);
+    simple_macro!(3831);
+    simple_macro!(3832);
+    simple_macro!(3833);
+    simple_macro!(3834);
+    simple_macro!(3835);
+    simple_macro!(3836);
+    simple_macro!(3837);
+    simple_macro!(3838);
+    simple_macro!(3839);
+    simple_macro!(3840);
+    simple_macro!(3841);
+    simple_macro!(3842);
+    simple_macro!(3843);
+    simple_macro!(3844);
+    simple_macro!(3845);
+    simple_macro!(3846);
+    simple_macro!(3847);
+    simple_macro!(3848);
+    simple_macro!(3849);
+    simple_macro!(3850);
+    simple_macro!(3851);
+    simple_macro!(3852);
+    simple_macro!(3853);
+    simple_macro!(3854);
+    simple_macro!(3855);
+    simple_macro!(3856);
+    simple_macro!(3857);
+    simple_macro!(3858);
+    simple_macro!(3859);
+    simple_macro!(3860);
+    simple_macro!(3861);
+    simple_macro!(3862);
+    simple_macro!(3863);
+    simple_macro!(3864);
+    simple_macro!(3865);
+    simple_macro!(3866);
+    simple_macro!(3867);
+    simple_macro!(3868);
+    simple_macro!(3869);
+    simple_macro!(3870);
+    simple_macro!(3871);
+    simple_macro!(3872);
+    simple_macro!(3873);
+    simple_macro!(3874);
+    simple_macro!(3875);
+    simple_macro!(3876);
+    simple_macro!(3877);
+    simple_macro!(3878);
+    simple_macro!(3879);
+    simple_macro!(3880);
+    simple_macro!(3881);
+    simple_macro!(3882);
+    simple_macro!(3883);
+    simple_macro!(3884);
+    simple_macro!(3885);
+    simple_macro!(3886);
+    simple_macro!(3887);
+    simple_macro!(3888);
+    simple_macro!(3889);
+    simple_macro!(3890);
+    simple_macro!(3891);
+    simple_macro!(3892);
+    simple_macro!(3893);
+    simple_macro!(3894);
+    simple_macro!(3895);
+    simple_macro!(3896);
+    simple_macro!(3897);
+    simple_macro!(3898);
+    simple_macro!(3899);
+    simple_macro!(3900);
+    simple_macro!(3901);
+    simple_macro!(3902);
+    simple_macro!(3903);
+    simple_macro!(3904);
+    simple_macro!(3905);
+    simple_macro!(3906);
+    simple_macro!(3907);
+    simple_macro!(3908);
+    simple_macro!(3909);
+    simple_macro!(3910);
+    simple_macro!(3911);
+    simple_macro!(3912);
+    simple_macro!(3913);
+    simple_macro!(3914);
+    simple_macro!(3915);
+    simple_macro!(3916);
+    simple_macro!(3917);
+    simple_macro!(3918);
+    simple_macro!(3919);
+    simple_macro!(3920);
+    simple_macro!(3921);
+    simple_macro!(3922);
+    simple_macro!(3923);
+    simple_macro!(3924);
+    simple_macro!(3925);
+    simple_macro!(3926);
+    simple_macro!(3927);
+    simple_macro!(3928);
+    simple_macro!(3929);
+    simple_macro!(3930);
+    simple_macro!(3931);
+    simple_macro!(3932);
+    simple_macro!(3933);
+    simple_macro!(3934);
+    simple_macro!(3935);
+    simple_macro!(3936);
+    simple_macro!(3937);
+    simple_macro!(3938);
+    simple_macro!(3939);
+    simple_macro!(3940);
+    simple_macro!(3941);
+    simple_macro!(3942);
+    simple_macro!(3943);
+    simple_macro!(3944);
+    simple_macro!(3945);
+    simple_macro!(3946);
+    simple_macro!(3947);
+    simple_macro!(3948);
+    simple_macro!(3949);
+    simple_macro!(3950);
+    simple_macro!(3951);
+    simple_macro!(3952);
+    simple_macro!(3953);
+    simple_macro!(3954);
+    simple_macro!(3955);
+    simple_macro!(3956);
+    simple_macro!(3957);
+    simple_macro!(3958);
+    simple_macro!(3959);
+    simple_macro!(3960);
+    simple_macro!(3961);
+    simple_macro!(3962);
+    simple_macro!(3963);
+    simple_macro!(3964);
+    simple_macro!(3965);
+    simple_macro!(3966);
+    simple_macro!(3967);
+    simple_macro!(3968);
+    simple_macro!(3969);
+    simple_macro!(3970);
+    simple_macro!(3971);
+    simple_macro!(3972);
+    simple_macro!(3973);
+    simple_macro!(3974);
+    simple_macro!(3975);
+    simple_macro!(3976);
+    simple_macro!(3977);
+    simple_macro!(3978);
+    simple_macro!(3979);
+    simple_macro!(3980);
+    simple_macro!(3981);
+    simple_macro!(3982);
+    simple_macro!(3983);
+    simple_macro!(3984);
+    simple_macro!(3985);
+    simple_macro!(3986);
+    simple_macro!(3987);
+    simple_macro!(3988);
+    simple_macro!(3989);
+    simple_macro!(3990);
+    simple_macro!(3991);
+    simple_macro!(3992);
+    simple_macro!(3993);
+    simple_macro!(3994);
+    simple_macro!(3995);
+    simple_macro!(3996);
+    simple_macro!(3997);
+    simple_macro!(3998);
+    simple_macro!(3999);
+    simple_macro!(4000);
+    simple_macro!(4001);
+    simple_macro!(4002);
+    simple_macro!(4003);
+    simple_macro!(4004);
+    simple_macro!(4005);
+    simple_macro!(4006);
+    simple_macro!(4007);
+    simple_macro!(4008);
+    simple_macro!(4009);
+    simple_macro!(4010);
+    simple_macro!(4011);
+    simple_macro!(4012);
+    simple_macro!(4013);
+    simple_macro!(4014);
+    simple_macro!(4015);
+    simple_macro!(4016);
+    simple_macro!(4017);
+    simple_macro!(4018);
+    simple_macro!(4019);
+    simple_macro!(4020);
+    simple_macro!(4021);
+    simple_macro!(4022);
+    simple_macro!(4023);
+    simple_macro!(4024);
+    simple_macro!(4025);
+    simple_macro!(4026);
+    simple_macro!(4027);
+    simple_macro!(4028);
+    simple_macro!(4029);
+    simple_macro!(4030);
+    simple_macro!(4031);
+    simple_macro!(4032);
+    simple_macro!(4033);
+    simple_macro!(4034);
+    simple_macro!(4035);
+    simple_macro!(4036);
+    simple_macro!(4037);
+    simple_macro!(4038);
+    simple_macro!(4039);
+    simple_macro!(4040);
+    simple_macro!(4041);
+    simple_macro!(4042);
+    simple_macro!(4043);
+    simple_macro!(4044);
+    simple_macro!(4045);
+    simple_macro!(4046);
+    simple_macro!(4047);
+    simple_macro!(4048);
+    simple_macro!(4049);
+    simple_macro!(4050);
+    simple_macro!(4051);
+    simple_macro!(4052);
+    simple_macro!(4053);
+    simple_macro!(4054);
+    simple_macro!(4055);
+    simple_macro!(4056);
+    simple_macro!(4057);
+    simple_macro!(4058);
+    simple_macro!(4059);
+    simple_macro!(4060);
+    simple_macro!(4061);
+    simple_macro!(4062);
+    simple_macro!(4063);
+    simple_macro!(4064);
+    simple_macro!(4065);
+    simple_macro!(4066);
+    simple_macro!(4067);
+    simple_macro!(4068);
+    simple_macro!(4069);
+    simple_macro!(4070);
+    simple_macro!(4071);
+    simple_macro!(4072);
+    simple_macro!(4073);
+    simple_macro!(4074);
+    simple_macro!(4075);
+    simple_macro!(4076);
+    simple_macro!(4077);
+    simple_macro!(4078);
+    simple_macro!(4079);
+    simple_macro!(4080);
+    simple_macro!(4081);
+    simple_macro!(4082);
+    simple_macro!(4083);
+    simple_macro!(4084);
+    simple_macro!(4085);
+    simple_macro!(4086);
+    simple_macro!(4087);
+    simple_macro!(4088);
+    simple_macro!(4089);
+    simple_macro!(4090);
+    simple_macro!(4091);
+    simple_macro!(4092);
+    simple_macro!(4093);
+    simple_macro!(4094);
+    simple_macro!(4095);
+    simple_macro!(4096);
+    simple_macro!(4097);
+}
+
+fn main() {
+    uncollapsed_debuginfo();
+}
diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs
index b35af76da3e..af1c20976d7 100644
--- a/tests/ui/delegation/unsupported.rs
+++ b/tests/ui/delegation/unsupported.rs
@@ -10,15 +10,11 @@ mod opaque {
     mod to_reuse {
         use super::Trait;
 
-        pub fn opaque_ret() -> impl Trait { unimplemented!() }
-        //~^ warn: this function depends on never type fallback being `()`
-        //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+        pub fn opaque_ret() -> impl Trait { () }
     }
 
     trait ToReuse {
-        fn opaque_ret() -> impl Trait { unimplemented!() }
-        //~^ warn: this function depends on never type fallback being `()`
-        //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+        fn opaque_ret() -> impl Trait { () }
     }
 
     // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls.
diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr
index 9391763dca2..2b0bcf9d84e 100644
--- a/tests/ui/delegation/unsupported.stderr
+++ b/tests/ui/delegation/unsupported.stderr
@@ -1,74 +1,43 @@
-error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:25:5: 25:24>::{synthetic#0}`
-  --> $DIR/unsupported.rs:26:25
+error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:21:5: 21:24>::{synthetic#0}`
+  --> $DIR/unsupported.rs:22:25
    |
 LL |         reuse to_reuse::opaque_ret;
    |                         ^^^^^^^^^^
    |
 note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
-  --> $DIR/unsupported.rs:26:25
+  --> $DIR/unsupported.rs:22:25
    |
 LL |         reuse to_reuse::opaque_ret;
    |                         ^^^^^^^^^^
-   = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:25:5: 25:24>::{synthetic#0}`, completing the cycle
-note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:25:5: 25:24>` is well-formed
-  --> $DIR/unsupported.rs:25:5
+   = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:21:5: 21:24>::{synthetic#0}`, completing the cycle
+note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:21:5: 21:24>` is well-formed
+  --> $DIR/unsupported.rs:21:5
    |
 LL |     impl ToReuse for u8 {
    |     ^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-warning: this function depends on never type fallback being `()`
-  --> $DIR/unsupported.rs:13:9
-   |
-LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
-   = help: specify the types explicitly
-note: in edition 2024, the requirement `!: opaque::Trait` will fail
-  --> $DIR/unsupported.rs:13:32
-   |
-LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
-   |                                ^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
-
-warning: this function depends on never type fallback being `()`
-  --> $DIR/unsupported.rs:19:9
-   |
-LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
-   = help: specify the types explicitly
-note: in edition 2024, the requirement `!: opaque::Trait` will fail
-  --> $DIR/unsupported.rs:19:28
-   |
-LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
-   |                            ^^^^^^^^^^
-
-error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:25>::{synthetic#0}`
-  --> $DIR/unsupported.rs:29:24
+error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:24:5: 24:25>::{synthetic#0}`
+  --> $DIR/unsupported.rs:25:24
    |
 LL |         reuse ToReuse::opaque_ret;
    |                        ^^^^^^^^^^
    |
 note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
-  --> $DIR/unsupported.rs:29:24
+  --> $DIR/unsupported.rs:25:24
    |
 LL |         reuse ToReuse::opaque_ret;
    |                        ^^^^^^^^^^
-   = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:28:5: 28:25>::{synthetic#0}`, completing the cycle
-note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:28:5: 28:25>` is well-formed
-  --> $DIR/unsupported.rs:28:5
+   = note: ...which again requires computing type of `opaque::<impl at $DIR/unsupported.rs:24:5: 24:25>::{synthetic#0}`, completing the cycle
+note: cycle used when checking that `opaque::<impl at $DIR/unsupported.rs:24:5: 24:25>` is well-formed
+  --> $DIR/unsupported.rs:24:5
    |
 LL |     impl ToReuse for u16 {
    |     ^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: recursive delegation is not supported yet
-  --> $DIR/unsupported.rs:42:22
+  --> $DIR/unsupported.rs:38:22
    |
 LL |         pub reuse to_reuse2::foo;
    |                              --- callee defined here
@@ -77,14 +46,14 @@ LL |     reuse to_reuse1::foo;
    |                      ^^^
 
 error[E0283]: type annotations needed
-  --> $DIR/unsupported.rs:52:18
+  --> $DIR/unsupported.rs:48:18
    |
 LL |     reuse Trait::foo;
    |                  ^^^ cannot infer type
    |
    = note: cannot satisfy `_: effects::Trait`
 
-error: aborting due to 4 previous errors; 2 warnings emitted
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0283, E0391.
 For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs
index 1d946a14aff..a46c856d38e 100644
--- a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs
+++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax
+
 #![deny(unknown_or_malformed_diagnostic_attributes)]
 
 #[diagnostic::unknown_attribute]
diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr
index a646d3613de..32be9db5317 100644
--- a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr
+++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr
@@ -1,11 +1,11 @@
 error: unknown diagnostic attribute
-  --> $DIR/deny_malformed_attribute.rs:3:15
+  --> $DIR/deny_malformed_attribute.rs:5:15
    |
 LL | #[diagnostic::unknown_attribute]
    |               ^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/deny_malformed_attribute.rs:1:9
+  --> $DIR/deny_malformed_attribute.rs:3:9
    |
 LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs
index 8b7467a17d0..b90dd0c7c94 100644
--- a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs
+++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs
@@ -1,5 +1,6 @@
 //@ edition:2021
 //@ aux-build:bad_on_unimplemented.rs
+//@ reference: attributes.diagnostic.on_unimplemented.syntax
 
 // Do not ICE when encountering a malformed `#[diagnostic::on_unimplemented]` annotation in a
 // dependency when incorrectly used (#124651).
diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr
index c3e56550b70..f1258ad6b9a 100644
--- a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr
+++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `(): bad_on_unimplemented::MissingAttr` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:22:18
+  --> $DIR/malformed_foreign_on_unimplemented.rs:23:18
    |
 LL |     missing_attr(());
    |     ------------ ^^ the trait `bad_on_unimplemented::MissingAttr` is not implemented for `()`
@@ -7,13 +7,13 @@ LL |     missing_attr(());
    |     required by a bound introduced by this call
    |
 note: required by a bound in `missing_attr`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:11:20
+  --> $DIR/malformed_foreign_on_unimplemented.rs:12:20
    |
 LL | fn missing_attr<T: MissingAttr>(_: T) {}
    |                    ^^^^^^^^^^^ required by this bound in `missing_attr`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::DuplicateAttr` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:23:20
+  --> $DIR/malformed_foreign_on_unimplemented.rs:24:20
    |
 LL |     duplicate_attr(());
    |     -------------- ^^ a
@@ -22,13 +22,13 @@ LL |     duplicate_attr(());
    |
    = help: the trait `bad_on_unimplemented::DuplicateAttr` is not implemented for `()`
 note: required by a bound in `duplicate_attr`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:12:22
+  --> $DIR/malformed_foreign_on_unimplemented.rs:13:22
    |
 LL | fn duplicate_attr<T: DuplicateAttr>(_: T) {}
    |                      ^^^^^^^^^^^^^ required by this bound in `duplicate_attr`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::NotMetaList` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:24:19
+  --> $DIR/malformed_foreign_on_unimplemented.rs:25:19
    |
 LL |     not_meta_list(());
    |     ------------- ^^ the trait `bad_on_unimplemented::NotMetaList` is not implemented for `()`
@@ -36,13 +36,13 @@ LL |     not_meta_list(());
    |     required by a bound introduced by this call
    |
 note: required by a bound in `not_meta_list`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:13:21
+  --> $DIR/malformed_foreign_on_unimplemented.rs:14:21
    |
 LL | fn not_meta_list<T: NotMetaList>(_: T) {}
    |                     ^^^^^^^^^^^ required by this bound in `not_meta_list`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::Empty` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:25:11
+  --> $DIR/malformed_foreign_on_unimplemented.rs:26:11
    |
 LL |     empty(());
    |     ----- ^^ the trait `bad_on_unimplemented::Empty` is not implemented for `()`
@@ -50,13 +50,13 @@ LL |     empty(());
    |     required by a bound introduced by this call
    |
 note: required by a bound in `empty`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:14:13
+  --> $DIR/malformed_foreign_on_unimplemented.rs:15:13
    |
 LL | fn empty<T: Empty>(_: T) {}
    |             ^^^^^ required by this bound in `empty`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::WrongDelim` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:26:17
+  --> $DIR/malformed_foreign_on_unimplemented.rs:27:17
    |
 LL |     wrong_delim(());
    |     ----------- ^^ the trait `bad_on_unimplemented::WrongDelim` is not implemented for `()`
@@ -64,13 +64,13 @@ LL |     wrong_delim(());
    |     required by a bound introduced by this call
    |
 note: required by a bound in `wrong_delim`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:15:19
+  --> $DIR/malformed_foreign_on_unimplemented.rs:16:19
    |
 LL | fn wrong_delim<T: WrongDelim>(_: T) {}
    |                   ^^^^^^^^^^ required by this bound in `wrong_delim`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::BadFormatter<()>` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:27:19
+  --> $DIR/malformed_foreign_on_unimplemented.rs:28:19
    |
 LL |     bad_formatter(());
    |     ------------- ^^ ()
@@ -79,13 +79,13 @@ LL |     bad_formatter(());
    |
    = help: the trait `bad_on_unimplemented::BadFormatter<()>` is not implemented for `()`
 note: required by a bound in `bad_formatter`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:16:21
+  --> $DIR/malformed_foreign_on_unimplemented.rs:17:21
    |
 LL | fn bad_formatter<T: BadFormatter<()>>(_: T) {}
    |                     ^^^^^^^^^^^^^^^^ required by this bound in `bad_formatter`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::NoImplicitArgs` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:28:22
+  --> $DIR/malformed_foreign_on_unimplemented.rs:29:22
    |
 LL |     no_implicit_args(());
    |     ---------------- ^^ test {}
@@ -94,13 +94,13 @@ LL |     no_implicit_args(());
    |
    = help: the trait `bad_on_unimplemented::NoImplicitArgs` is not implemented for `()`
 note: required by a bound in `no_implicit_args`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:17:24
+  --> $DIR/malformed_foreign_on_unimplemented.rs:18:24
    |
 LL | fn no_implicit_args<T: NoImplicitArgs>(_: T) {}
    |                        ^^^^^^^^^^^^^^ required by this bound in `no_implicit_args`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::MissingArg` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:29:17
+  --> $DIR/malformed_foreign_on_unimplemented.rs:30:17
    |
 LL |     missing_arg(());
    |     ----------- ^^ {missing}
@@ -109,13 +109,13 @@ LL |     missing_arg(());
    |
    = help: the trait `bad_on_unimplemented::MissingArg` is not implemented for `()`
 note: required by a bound in `missing_arg`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:18:19
+  --> $DIR/malformed_foreign_on_unimplemented.rs:19:19
    |
 LL | fn missing_arg<T: MissingArg>(_: T) {}
    |                   ^^^^^^^^^^ required by this bound in `missing_arg`
 
 error[E0277]: the trait bound `(): bad_on_unimplemented::BadArg` is not satisfied
-  --> $DIR/malformed_foreign_on_unimplemented.rs:30:13
+  --> $DIR/malformed_foreign_on_unimplemented.rs:31:13
    |
 LL |     bad_arg(());
    |     ------- ^^ {_}
@@ -124,7 +124,7 @@ LL |     bad_arg(());
    |
    = help: the trait `bad_on_unimplemented::BadArg` is not implemented for `()`
 note: required by a bound in `bad_arg`
-  --> $DIR/malformed_foreign_on_unimplemented.rs:19:15
+  --> $DIR/malformed_foreign_on_unimplemented.rs:20:15
    |
 LL | fn bad_arg<T: BadArg>(_: T) {}
    |               ^^^^^^ required by this bound in `bad_arg`
diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs
index f6957b1448d..02c1352482c 100644
--- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs
+++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs
@@ -1,4 +1,5 @@
 //@ check-pass
+//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax
 #[diagnostic::non_existing_attribute]
 //~^WARN unknown diagnostic attribute
 pub trait Bar {
diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
index c073ec9b103..753077b365e 100644
--- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
+++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
@@ -1,5 +1,5 @@
 warning: unknown diagnostic attribute
-  --> $DIR/non_existing_attributes_accepted.rs:2:15
+  --> $DIR/non_existing_attributes_accepted.rs:3:15
    |
 LL | #[diagnostic::non_existing_attribute]
    |               ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[diagnostic::non_existing_attribute]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: unknown diagnostic attribute
-  --> $DIR/non_existing_attributes_accepted.rs:7:15
+  --> $DIR/non_existing_attributes_accepted.rs:8:15
    |
 LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
    |               ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
index 3ca58b28181..44f269eb967 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
@@ -1,3 +1,4 @@
+//@ reference: attributes.diagnostic.on_unimplemented.invalid-string
 #[diagnostic::on_unimplemented(message = "{{Test } thing")]
 //~^WARN unmatched `}` found
 //~|WARN unmatched `}` found
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
index b4ed06cb63d..7fd51c7527f 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -1,5 +1,5 @@
 warning: unmatched `}` found
-  --> $DIR/broken_format.rs:1:32
+  --> $DIR/broken_format.rs:2:32
    |
 LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: positional format arguments are not allowed here
-  --> $DIR/broken_format.rs:6:32
+  --> $DIR/broken_format.rs:7:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {}")]
    |                                ^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")]
    = help: only named format arguments with the name of one of the generic types are allowed in this context
 
 warning: positional format arguments are not allowed here
-  --> $DIR/broken_format.rs:11:32
+  --> $DIR/broken_format.rs:12:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
    = help: only named format arguments with the name of one of the generic types are allowed in this context
 
 warning: invalid format specifier
-  --> $DIR/broken_format.rs:16:32
+  --> $DIR/broken_format.rs:17:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,19 +31,19 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
    = help: no format specifier are supported in this position
 
 warning: expected `}`, found `!`
-  --> $DIR/broken_format.rs:21:32
+  --> $DIR/broken_format.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unmatched `}` found
-  --> $DIR/broken_format.rs:21:32
+  --> $DIR/broken_format.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unmatched `}` found
-  --> $DIR/broken_format.rs:1:32
+  --> $DIR/broken_format.rs:2:32
    |
 LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: {{Test } thing
-  --> $DIR/broken_format.rs:35:13
+  --> $DIR/broken_format.rs:36:13
    |
 LL |     check_1(());
    |     ------- ^^ the trait `ImportantTrait1` is not implemented for `()`
@@ -59,18 +59,18 @@ LL |     check_1(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:4:1
+  --> $DIR/broken_format.rs:5:1
    |
 LL | trait ImportantTrait1 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_1`
-  --> $DIR/broken_format.rs:28:20
+  --> $DIR/broken_format.rs:29:20
    |
 LL | fn check_1(_: impl ImportantTrait1) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_1`
 
 warning: positional format arguments are not allowed here
-  --> $DIR/broken_format.rs:6:32
+  --> $DIR/broken_format.rs:7:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {}")]
    |                                ^^^^^^^^^^^^^^^^^^^
@@ -79,7 +79,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test {}
-  --> $DIR/broken_format.rs:37:13
+  --> $DIR/broken_format.rs:38:13
    |
 LL |     check_2(());
    |     ------- ^^ the trait `ImportantTrait2` is not implemented for `()`
@@ -87,18 +87,18 @@ LL |     check_2(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:9:1
+  --> $DIR/broken_format.rs:10:1
    |
 LL | trait ImportantTrait2 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_2`
-  --> $DIR/broken_format.rs:29:20
+  --> $DIR/broken_format.rs:30:20
    |
 LL | fn check_2(_: impl ImportantTrait2) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_2`
 
 warning: positional format arguments are not allowed here
-  --> $DIR/broken_format.rs:11:32
+  --> $DIR/broken_format.rs:12:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test {1}
-  --> $DIR/broken_format.rs:39:13
+  --> $DIR/broken_format.rs:40:13
    |
 LL |     check_3(());
    |     ------- ^^ the trait `ImportantTrait3` is not implemented for `()`
@@ -115,18 +115,18 @@ LL |     check_3(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:14:1
+  --> $DIR/broken_format.rs:15:1
    |
 LL | trait ImportantTrait3 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_3`
-  --> $DIR/broken_format.rs:30:20
+  --> $DIR/broken_format.rs:31:20
    |
 LL | fn check_3(_: impl ImportantTrait3) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_3`
 
 warning: invalid format specifier
-  --> $DIR/broken_format.rs:16:32
+  --> $DIR/broken_format.rs:17:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test ()
-  --> $DIR/broken_format.rs:41:13
+  --> $DIR/broken_format.rs:42:13
    |
 LL |     check_4(());
    |     ------- ^^ the trait `ImportantTrait4` is not implemented for `()`
@@ -143,18 +143,18 @@ LL |     check_4(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:19:1
+  --> $DIR/broken_format.rs:20:1
    |
 LL | trait ImportantTrait4 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_4`
-  --> $DIR/broken_format.rs:31:20
+  --> $DIR/broken_format.rs:32:20
    |
 LL | fn check_4(_: impl ImportantTrait4) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_4`
 
 warning: expected `}`, found `!`
-  --> $DIR/broken_format.rs:21:32
+  --> $DIR/broken_format.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +162,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unmatched `}` found
-  --> $DIR/broken_format.rs:21:32
+  --> $DIR/broken_format.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -170,7 +170,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test {Self:!}
-  --> $DIR/broken_format.rs:43:13
+  --> $DIR/broken_format.rs:44:13
    |
 LL |     check_5(());
    |     ------- ^^ the trait `ImportantTrait5` is not implemented for `()`
@@ -178,12 +178,12 @@ LL |     check_5(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:26:1
+  --> $DIR/broken_format.rs:27:1
    |
 LL | trait ImportantTrait5 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_5`
-  --> $DIR/broken_format.rs:32:20
+  --> $DIR/broken_format.rs:33:20
    |
 LL | fn check_5(_: impl ImportantTrait5) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_5`
diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs
index d7e257ef3bb..1173c939038 100644
--- a/tests/ui/traits/custom-on-unimplemented-diagnostic.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.diagnostic.on_unimplemented.intro
+//@ reference: attributes.diagnostic.on_unimplemented.keys
 #[diagnostic::on_unimplemented(message = "my message", label = "my label", note = "my note")]
 pub trait ProviderLt {}
 
diff --git a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr
index f9788360d06..4c1838620b3 100644
--- a/tests/ui/traits/custom-on-unimplemented-diagnostic.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/custom-on-unimplemented-diagnostic.stderr
@@ -1,5 +1,5 @@
 error[E0599]: my message
-  --> $DIR/custom-on-unimplemented-diagnostic.rs:15:7
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:17:7
    |
 LL | struct B;
    | -------- method `request` not found for this struct because it doesn't satisfy `B: ProviderExt` or `B: ProviderLt`
@@ -8,7 +8,7 @@ LL |     B.request();
    |       ^^^^^^^ my label
    |
 note: trait bound `B: ProviderLt` was not satisfied
-  --> $DIR/custom-on-unimplemented-diagnostic.rs:10:18
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:12:18
    |
 LL | impl<T: ?Sized + ProviderLt> ProviderExt for T {}
    |                  ^^^^^^^^^^  -----------     -
@@ -16,13 +16,13 @@ LL | impl<T: ?Sized + ProviderLt> ProviderExt for T {}
    |                  unsatisfied trait bound introduced here
    = note: my note
 note: the trait `ProviderLt` must be implemented
-  --> $DIR/custom-on-unimplemented-diagnostic.rs:2:1
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1
    |
 LL | pub trait ProviderLt {}
    | ^^^^^^^^^^^^^^^^^^^^
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `ProviderExt` defines an item `request`, perhaps you need to implement it
-  --> $DIR/custom-on-unimplemented-diagnostic.rs:4:1
+  --> $DIR/custom-on-unimplemented-diagnostic.rs:6:1
    |
 LL | pub trait ProviderExt {
    | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
index 30a85ff2199..b76b550fcb2 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
@@ -1,3 +1,7 @@
+//@ reference: attributes.diagnostic.on_unimplemented.format-parameters
+//@ reference: attributes.diagnostic.on_unimplemented.keys
+//@ reference: attributes.diagnostic.on_unimplemented.syntax
+//@ reference: attributes.diagnostic.on_unimplemented.invalid-formats
 #[diagnostic::on_unimplemented(
     on(_Self = "&str"),
     //~^WARN malformed `on_unimplemented` attribute
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
index e34b917f67e..bb455d92940 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
@@ -1,5 +1,5 @@
 warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:22:1
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:26:1
    |
 LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5
    |
 LL |     on(_Self = "&str"),
    |     ^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -15,7 +15,7 @@ LL |     on(_Self = "&str"),
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5
    |
 LL |     parent_label = "in this scope",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -23,7 +23,7 @@ LL |     parent_label = "in this scope",
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:5
    |
 LL |     append_const_msg
    |     ^^^^^^^^^^^^^^^^ invalid option found here
@@ -31,7 +31,7 @@ LL |     append_const_msg
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:21:32
    |
 LL | #[diagnostic::on_unimplemented = "Message"]
    |                                ^^^^^^^^^^^ invalid option found here
@@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "Message"]
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: there is no parameter `from_desugaring` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `direct` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -55,7 +55,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `cause` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `integral` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `integer` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -79,7 +79,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `float` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `_Self` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `crate_local` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `Trait` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: there is no parameter `ItemContext` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -119,7 +119,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5
    |
 LL |     on(_Self = "&str"),
    |     ^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -128,7 +128,7 @@ LL |     on(_Self = "&str"),
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5
    |
 LL |     parent_label = "in this scope",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -137,7 +137,7 @@ LL |     parent_label = "in this scope",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:5
    |
 LL |     append_const_msg
    |     ^^^^^^^^^^^^^^^^ invalid option found here
@@ -146,7 +146,7 @@ LL |     append_const_msg
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: trait has `()` and `i32` as params
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15
    |
 LL |     takes_foo(());
    |     --------- ^^ trait has `()` and `i32` as params
@@ -156,18 +156,18 @@ LL |     takes_foo(());
    = help: the trait `Foo<i32>` is not implemented for `()`
    = note: trait has `()` and `i32` as params
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:1
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:1
    |
 LL | trait Foo<T> {}
    | ^^^^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22
    |
 LL | fn takes_foo(_: impl Foo<i32>) {}
    |                      ^^^^^^^^ required by this bound in `takes_foo`
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:21:32
    |
 LL | #[diagnostic::on_unimplemented = "Message"]
    |                                ^^^^^^^^^^^ invalid option found here
@@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented = "Message"]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15
    |
 LL |     takes_bar(());
    |     --------- ^^ the trait `Bar` is not implemented for `()`
@@ -185,13 +185,13 @@ LL |     takes_bar(());
    |
    = help: the trait `Bar` is implemented for `i32`
 note: required by a bound in `takes_bar`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:22
    |
 LL | fn takes_bar(_: impl Bar) {}
    |                      ^^^ required by this bound in `takes_bar`
 
 warning: there is no parameter `from_desugaring` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -200,7 +200,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `direct` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `cause` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -218,7 +218,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `integral` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -227,7 +227,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `integer` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
    |
 LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -236,7 +236,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `float` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -245,7 +245,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `_Self` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -254,7 +254,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `crate_local` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -263,7 +263,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `Trait` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -272,7 +272,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: there is no parameter `ItemContext` on trait `Baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
    |
 LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -281,7 +281,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15
    |
 LL |     takes_baz(());
    |     --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}
@@ -290,12 +290,12 @@ LL |     takes_baz(());
    |
    = help: the trait `Baz` is not implemented for `()`
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:1
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:1
    |
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `takes_baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22
    |
 LL | fn takes_baz(_: impl Baz) {}
    |                      ^^^ required by this bound in `takes_baz`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
index b4234066bb1..8328c10d2a0 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.diagnostic.on_unimplemented.syntax
+//@ reference: attributes.diagnostic.on_unimplemented.unknown-keys
 #[diagnostic::on_unimplemented(unsupported = "foo")]
 //~^WARN malformed `on_unimplemented` attribute
 //~|WARN malformed `on_unimplemented` attribute
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
index dc0c1948236..11263580b15 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -1,5 +1,5 @@
 warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:8:1
    |
 LL | #[diagnostic::on_unimplemented(message = "Baz")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Baz")]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
    |
 LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
    |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
    |                                                  ^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
    |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -31,7 +31,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:32
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32
    |
 LL | #[diagnostic::on_unimplemented = "boom"]
    |                                ^^^^^^^^ invalid option found here
@@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "boom"]
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: missing options for `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
    |
 LL | #[diagnostic::on_unimplemented]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL | #[diagnostic::on_unimplemented]
    = help: at least one of the `message`, `note` and `label` options are expected
 
 warning: there is no parameter `DoesNotExist` on trait `Test`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32
    |
 LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -55,7 +55,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    = help: expect either a generic argument name or `{Self}` as format argument
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
    |
 LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
    |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -64,7 +64,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14
    |
 LL |     take_foo(1_i32);
    |     -------- ^^^^^ the trait `Foo` is not implemented for `i32`
@@ -72,18 +72,18 @@ LL |     take_foo(1_i32);
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:4:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `take_foo`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21
    |
 LL | fn take_foo(_: impl Foo) {}
    |                     ^^^ required by this bound in `take_foo`
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
    |                                                  ^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -92,7 +92,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14
    |
 LL |     take_baz(1_i32);
    |     -------- ^^^^^ the trait `Baz` is not implemented for `i32`
@@ -100,18 +100,18 @@ LL |     take_baz(1_i32);
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:13:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:1
    |
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `take_baz`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21
    |
 LL | fn take_baz(_: impl Baz) {}
    |                     ^^^ required by this bound in `take_baz`
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
    |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -120,7 +120,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:15
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15
    |
 LL |     take_boom(1_i32);
    |     --------- ^^^^^ the trait `Boom` is not implemented for `i32`
@@ -128,18 +128,18 @@ LL |     take_boom(1_i32);
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:18:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:1
    |
 LL | trait Boom {}
    | ^^^^^^^^^^
 note: required by a bound in `take_boom`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:22
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22
    |
 LL | fn take_boom(_: impl Boom) {}
    |                      ^^^^ required by this bound in `take_boom`
 
 warning: missing options for `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
    |
 LL | #[diagnostic::on_unimplemented]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL | #[diagnostic::on_unimplemented]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `i32: Whatever` is not satisfied
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:19
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19
    |
 LL |     take_whatever(1_i32);
    |     ------------- ^^^^^ the trait `Whatever` is not implemented for `i32`
@@ -156,18 +156,18 @@ LL |     take_whatever(1_i32);
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1
    |
 LL | trait Whatever {}
    | ^^^^^^^^^^^^^^
 note: required by a bound in `take_whatever`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:26
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26
    |
 LL | fn take_whatever(_: impl Whatever) {}
    |                          ^^^^^^^^ required by this bound in `take_whatever`
 
 warning: there is no parameter `DoesNotExist` on trait `Test`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32
    |
 LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: {DoesNotExist}
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:15
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15
    |
 LL |     take_test(());
    |     --------- ^^ the trait `Test` is not implemented for `()`
@@ -184,12 +184,12 @@ LL |     take_test(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1
    |
 LL | trait Test {}
    | ^^^^^^^^^^
 note: required by a bound in `take_test`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22
    |
 LL | fn take_test(_: impl Test) {}
    |                      ^^^^ required by this bound in `take_test`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs
index 7eaff73dca1..dff209d4761 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.rs
@@ -1,4 +1,5 @@
 //@ aux-build:other.rs
+//@ reference: attributes.diagnostic.on_unimplemented.intro
 
 extern crate other;
 
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr
index a9968538d0d..c0dd6d9628a 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/error_is_shown_in_downstream_crates.stderr
@@ -1,5 +1,5 @@
 error[E0277]: Message
-  --> $DIR/error_is_shown_in_downstream_crates.rs:10:14
+  --> $DIR/error_is_shown_in_downstream_crates.rs:11:14
    |
 LL |     take_foo(());
    |     -------- ^^ label
@@ -9,7 +9,7 @@ LL |     take_foo(());
    = help: the trait `Foo` is not implemented for `()`
    = note: Note
 note: required by a bound in `take_foo`
-  --> $DIR/error_is_shown_in_downstream_crates.rs:7:21
+  --> $DIR/error_is_shown_in_downstream_crates.rs:8:21
    |
 LL | fn take_foo(_: impl Foo) {}
    |                     ^^^ required by this bound in `take_foo`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
index 5b25fb234bc..c638681173d 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.diagnostic.on_unimplemented.repetition
+//@ reference: attributes.diagnostic.on_unimplemented.syntax
 #[diagnostic::on_unimplemented(
     if(Self = "()"),
     //~^WARN malformed `on_unimplemented` attribute
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
index 56d125e20e5..e00846da77b 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
@@ -1,5 +1,5 @@
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
    |
 LL |     if(Self = "()"),
    |     ^^^^^^^^^^^^^^^ invalid option found here
@@ -8,7 +8,7 @@ LL |     if(Self = "()"),
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: `message` is ignored due to previous definition of `message`
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32
    |
 LL |     message = "custom message",
    |     -------------------------- `message` is first declared here
@@ -17,7 +17,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")]
    |                                ^^^^^^^^^^^^^^^^^^^^^^ `message` is already declared here
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
    |
 LL |     if(Self = "()"),
    |     ^^^^^^^^^^^^^^^ invalid option found here
@@ -26,7 +26,7 @@ LL |     if(Self = "()"),
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: `message` is ignored due to previous definition of `message`
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32
    |
 LL |     message = "custom message",
    |     -------------------------- `message` is first declared here
@@ -37,7 +37,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: custom message
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15
    |
 LL |     takes_foo(());
    |     --------- ^^ fallback label
@@ -48,12 +48,12 @@ LL |     takes_foo(());
    = note: custom note
    = note: fallback note
 help: this trait has no implementations, consider adding one
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22
+  --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22
    |
 LL | fn takes_foo(_: impl Foo) {}
    |                      ^^^ required by this bound in `takes_foo`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs
index a5982f6492c..dc0f850031e 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs
@@ -1,3 +1,4 @@
+//@ reference: attributes.diagnostic.on_unimplemented.note-repetition
 #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz", note = "Boom")]
 trait Foo {}
 
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr
index 93a0d0b3f41..6567269be3b 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr
@@ -1,5 +1,5 @@
 error[E0277]: Foo
-  --> $DIR/multiple_notes.rs:12:15
+  --> $DIR/multiple_notes.rs:13:15
    |
 LL |     takes_foo(());
    |     --------- ^^ Bar
@@ -10,18 +10,18 @@ LL |     takes_foo(());
    = note: Baz
    = note: Boom
 help: this trait has no implementations, consider adding one
-  --> $DIR/multiple_notes.rs:2:1
+  --> $DIR/multiple_notes.rs:3:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/multiple_notes.rs:8:22
+  --> $DIR/multiple_notes.rs:9:22
    |
 LL | fn takes_foo(_: impl Foo) {}
    |                      ^^^ required by this bound in `takes_foo`
 
 error[E0277]: Bar
-  --> $DIR/multiple_notes.rs:14:15
+  --> $DIR/multiple_notes.rs:15:15
    |
 LL |     takes_bar(());
    |     --------- ^^ Foo
@@ -32,12 +32,12 @@ LL |     takes_bar(());
    = note: Baz
    = note: Baz2
 help: this trait has no implementations, consider adding one
-  --> $DIR/multiple_notes.rs:6:1
+  --> $DIR/multiple_notes.rs:7:1
    |
 LL | trait Bar {}
    | ^^^^^^^^^
 note: required by a bound in `takes_bar`
-  --> $DIR/multiple_notes.rs:9:22
+  --> $DIR/multiple_notes.rs:10:22
    |
 LL | fn takes_bar(_: impl Bar) {}
    |                      ^^^ required by this bound in `takes_bar`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs
index 7ca03127759..e584077c643 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.diagnostic.on_unimplemented.intro
+//@ reference: attributes.diagnostic.on_unimplemented.keys
 #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz")]
 trait Foo {}
 
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr
index 6b17f40c6dd..de57f7044bf 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr
@@ -1,5 +1,5 @@
 error[E0277]: Foo
-  --> $DIR/on_unimplemented_simple.rs:7:15
+  --> $DIR/on_unimplemented_simple.rs:9:15
    |
 LL |     takes_foo(());
    |     --------- ^^ Bar
@@ -9,12 +9,12 @@ LL |     takes_foo(());
    = help: the trait `Foo` is not implemented for `()`
    = note: Baz
 help: this trait has no implementations, consider adding one
-  --> $DIR/on_unimplemented_simple.rs:2:1
+  --> $DIR/on_unimplemented_simple.rs:4:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/on_unimplemented_simple.rs:4:22
+  --> $DIR/on_unimplemented_simple.rs:6:22
    |
 LL | fn takes_foo(_: impl Foo) {}
    |                      ^^^ required by this bound in `takes_foo`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs
index 8c0b8150417..d0eb608c40f 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs
@@ -1,3 +1,4 @@
+//@ reference: attributes.diagnostic.on_unimplemented.repetition
 #[diagnostic::on_unimplemented(
     message = "first message",
     label = "first label",
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr
index 43ab6bf25a1..feafe2cee76 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr
@@ -1,5 +1,5 @@
 warning: `message` is ignored due to previous definition of `message`
-  --> $DIR/report_warning_on_duplicated_options.rs:7:5
+  --> $DIR/report_warning_on_duplicated_options.rs:8:5
    |
 LL |     message = "first message",
    |     ------------------------- `message` is first declared here
@@ -10,7 +10,7 @@ LL |     message = "second message",
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: `label` is ignored due to previous definition of `label`
-  --> $DIR/report_warning_on_duplicated_options.rs:10:5
+  --> $DIR/report_warning_on_duplicated_options.rs:11:5
    |
 LL |     label = "first label",
    |     --------------------- `label` is first declared here
@@ -19,7 +19,7 @@ LL |     label = "second label",
    |     ^^^^^^^^^^^^^^^^^^^^^^ `label` is already declared here
 
 warning: `message` is ignored due to previous definition of `message`
-  --> $DIR/report_warning_on_duplicated_options.rs:7:5
+  --> $DIR/report_warning_on_duplicated_options.rs:8:5
    |
 LL |     message = "first message",
    |     ------------------------- `message` is first declared here
@@ -30,7 +30,7 @@ LL |     message = "second message",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: `label` is ignored due to previous definition of `label`
-  --> $DIR/report_warning_on_duplicated_options.rs:10:5
+  --> $DIR/report_warning_on_duplicated_options.rs:11:5
    |
 LL |     label = "first label",
    |     --------------------- `label` is first declared here
@@ -41,7 +41,7 @@ LL |     label = "second label",
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: first message
-  --> $DIR/report_warning_on_duplicated_options.rs:21:15
+  --> $DIR/report_warning_on_duplicated_options.rs:22:15
    |
 LL |     takes_foo(());
    |     --------- ^^ first label
@@ -52,12 +52,12 @@ LL |     takes_foo(());
    = note: custom note
    = note: second note
 help: this trait has no implementations, consider adding one
-  --> $DIR/report_warning_on_duplicated_options.rs:15:1
+  --> $DIR/report_warning_on_duplicated_options.rs:16:1
    |
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/report_warning_on_duplicated_options.rs:18:22
+  --> $DIR/report_warning_on_duplicated_options.rs:19:22
    |
 LL | fn takes_foo(_: impl Foo) {}
    |                      ^^^ required by this bound in `takes_foo`
diff --git a/tests/ui/diagnostic_namespace/suggest_typos.rs b/tests/ui/diagnostic_namespace/suggest_typos.rs
index b25f097a8ad..6fa4f800462 100644
--- a/tests/ui/diagnostic_namespace/suggest_typos.rs
+++ b/tests/ui/diagnostic_namespace/suggest_typos.rs
@@ -1,3 +1,4 @@
+//@ reference: attributes.diagnostic.namespace.unknown-invalid-syntax
 #![deny(unknown_or_malformed_diagnostic_attributes)]
 
 #[diagnostic::onunimplemented]
diff --git a/tests/ui/diagnostic_namespace/suggest_typos.stderr b/tests/ui/diagnostic_namespace/suggest_typos.stderr
index 307311258f2..ff4ee9717d4 100644
--- a/tests/ui/diagnostic_namespace/suggest_typos.stderr
+++ b/tests/ui/diagnostic_namespace/suggest_typos.stderr
@@ -1,11 +1,11 @@
 error: unknown diagnostic attribute
-  --> $DIR/suggest_typos.rs:3:15
+  --> $DIR/suggest_typos.rs:4:15
    |
 LL | #[diagnostic::onunimplemented]
    |               ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/suggest_typos.rs:1:9
+  --> $DIR/suggest_typos.rs:2:9
    |
 LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented]
    |               ~~~~~~~~~~~~~~~~
 
 error: unknown diagnostic attribute
-  --> $DIR/suggest_typos.rs:8:15
+  --> $DIR/suggest_typos.rs:9:15
    |
 LL | #[diagnostic::un_onimplemented]
    |               ^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | #[diagnostic::on_unimplemented]
    |               ~~~~~~~~~~~~~~~~
 
 error: unknown diagnostic attribute
-  --> $DIR/suggest_typos.rs:13:15
+  --> $DIR/suggest_typos.rs:14:15
    |
 LL | #[diagnostic::on_implemented]
    |               ^^^^^^^^^^^^^^
diff --git a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
index fde542c756f..508e7bdbf99 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
@@ -1,9 +1,10 @@
-// This test is to demonstrate that the lint is gated behind Edition and
-// is triggered only for Edition 2021 and before.
+// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is used
+// because this is a migration lint.
+// Only `cargo fix --edition 2024` shall activate this lint.
 
 //@ check-pass
-//@ edition: 2024
 //@ compile-flags: -Z unstable-options
+//@ edition: 2024
 
 #![deny(tail_expr_drop_order)]
 
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs
index d61abae5187..0fabc1f085c 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order.rs
@@ -1,13 +1,26 @@
-//@ edition: 2021
-
 // Edition 2024 lint for change in drop order at tail expression
 // This lint is to capture potential change in program semantics
 // due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
+//@ edition: 2021
+//@ build-fail
 
-#![deny(tail_expr_drop_order)]
+#![deny(tail_expr_drop_order)] //~ NOTE: the lint level is defined here
+#![allow(dropping_copy_types)]
 
 struct LoudDropper;
 impl Drop for LoudDropper {
+    //~^ NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `future` invokes this custom destructor
+    //~| NOTE: `_x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
     fn drop(&mut self) {
         // This destructor should be considered significant because it is a custom destructor
         // and we will assume that the destructor can generate side effects arbitrarily so that
@@ -23,30 +36,70 @@ impl LoudDropper {
 
 fn should_lint() -> i32 {
     let x = LoudDropper;
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
     // Should lint
     x.get() + LoudDropper.get()
-    //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
     //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
 }
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 
-fn should_lint_closure() -> impl FnOnce() -> i32 {
+fn should_not_lint_closure() -> impl FnOnce() -> i32 {
     let x = LoudDropper;
-    move || x.get() + LoudDropper.get()
-    //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-    //~| WARN: this changes meaning in Rust 2024
+    move || {
+        // Should not lint because ...
+        x.get() + LoudDropper.get()
+    }
+    // ^ closure captures like `x` are always dropped last by contract
+}
+
+fn should_lint_in_nested_items() {
+    fn should_lint_me() -> i32 {
+        let x = LoudDropper;
+        //~^ NOTE: `x` calls a custom destructor
+        //~| NOTE: `x` will be dropped later as of Edition 2024
+        // Should lint
+        x.get() + LoudDropper.get()
+        //~^ ERROR: relative drop order changing in Rust 2024
+        //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+        //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+        //~| NOTE: for more information, see issue #123739
+    }
+    //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 }
 
+fn should_not_lint_params(x: LoudDropper) -> i32 {
+    // Should not lint because ...
+    x.get() + LoudDropper.get()
+}
+// ^ function parameters like `x` are always dropped last
+
 fn should_not_lint() -> i32 {
     let x = LoudDropper;
     // Should not lint
     x.get()
 }
 
-fn should_not_lint_in_nested_block() -> i32 {
+fn should_lint_in_nested_block() -> i32 {
     let x = LoudDropper;
-    // Should not lint because Edition 2021 drops temporaries in blocks earlier already
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
     { LoudDropper.get() }
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
 }
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 
 fn should_not_lint_in_match_arm() -> i32 {
     let x = LoudDropper;
@@ -56,14 +109,144 @@ fn should_not_lint_in_match_arm() -> i32 {
     }
 }
 
-fn should_lint_in_nested_items() {
-    fn should_lint_me() -> i32 {
+fn should_not_lint_when_consumed() -> (LoudDropper, i32) {
+    let x = LoudDropper;
+    // Should not lint because `LoudDropper` is consumed by the return value
+    (LoudDropper, x.get())
+}
+
+struct MyAdt {
+    a: LoudDropper,
+    b: LoudDropper,
+}
+
+fn should_not_lint_when_consumed_in_ctor() -> MyAdt {
+    let a = LoudDropper;
+    // Should not lint
+    MyAdt { a, b: LoudDropper }
+}
+
+fn should_not_lint_when_moved() -> i32 {
+    let x = LoudDropper;
+    drop(x);
+    // Should not lint because `x` is not live
+    LoudDropper.get()
+}
+
+fn should_lint_into_async_body() -> i32 {
+    async fn f() {
+        async fn f() {}
         let x = LoudDropper;
-        // Should lint
-        x.get() + LoudDropper.get()
-        //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-        //~| WARN: this changes meaning in Rust 2024
+        f().await;
+        drop(x);
+    }
+
+    let future = f();
+    //~^ NOTE: `future` calls a custom destructor
+    //~| NOTE: `future` will be dropped later as of Edition 2024
+    LoudDropper.get()
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_lint_generics<T: Default>() -> &'static str {
+    fn extract<T>(_: &T) -> &'static str {
+        todo!()
+    }
+    let x = T::default();
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
+    extract(&T::default())
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_lint_adt() -> i32 {
+    let x: Result<LoudDropper, ()> = Ok(LoudDropper);
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
+    LoudDropper.get()
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_not_lint_insign_dtor() -> i32 {
+    let x = String::new();
+    LoudDropper.get()
+}
+
+fn should_lint_with_dtor_span() -> i32 {
+    struct LoudDropper3;
+    impl Drop for LoudDropper3 {
+        //~^ NOTE: `#1` invokes this custom destructor
+        fn drop(&mut self) {
+            println!("loud drop");
+        }
     }
+    impl LoudDropper3 {
+        fn get(&self) -> i32 {
+            0
+        }
+    }
+    struct LoudDropper2;
+    impl Drop for LoudDropper2 {
+        //~^ NOTE: `x` invokes this custom destructor
+        fn drop(&mut self) {
+            println!("loud drop");
+        }
+    }
+    impl LoudDropper2 {
+        fn get(&self) -> i32 {
+            0
+        }
+    }
+
+    let x = LoudDropper2;
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
+    LoudDropper3.get()
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_lint_with_transient_drops() {
+    drop((
+        {
+            LoudDropper.get()
+            //~^ ERROR: relative drop order changing in Rust 2024
+            //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+            //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+            //~| WARN: this changes meaning in Rust 2024
+            //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+            //~| NOTE: for more information, see issue #123739
+        },
+        {
+            let _x = LoudDropper;
+            //~^ NOTE: `_x` calls a custom destructor
+            //~| NOTE: `_x` will be dropped later as of Edition 2024
+        },
+    ));
+    //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 }
 
 fn main() {}
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr
index 6775c4ce6d1..f0da24605e6 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr
@@ -1,42 +1,335 @@
-error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:27:15
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:42:15
    |
 LL |     let x = LoudDropper;
-   |         - these values have significant drop implementation and will observe changes in drop order under Edition 2024
-LL |     // Should lint
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
 LL |     x.get() + LoudDropper.get()
    |               ^^^^^^^^^^^
+   |               |
+   |               this value will be stored in a temporary; let us call it `#1`
+   |               up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 note: the lint level is defined here
   --> $DIR/lint-tail-expr-drop-order.rs:7:9
    |
 LL | #![deny(tail_expr_drop_order)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:34:23
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:67:19
+   |
+LL |         let x = LoudDropper;
+   |             -
+   |             |
+   |             `x` calls a custom destructor
+   |             `x` will be dropped later as of Edition 2024
+...
+LL |         x.get() + LoudDropper.get()
+   |                   ^^^^^^^^^^^
+   |                   |
+   |                   this value will be stored in a temporary; let us call it `#1`
+   |                   up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL |     }
+   |     - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:94:7
    |
 LL |     let x = LoudDropper;
-   |         - these values have significant drop implementation and will observe changes in drop order under Edition 2024
-LL |     move || x.get() + LoudDropper.get()
-   |                       ^^^^^^^^^^^
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     { LoudDropper.get() }
+   |       ^^^^^^^^^^^
+   |       |
+   |       this value will be stored in a temporary; let us call it `#1`
+   |       up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
-error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:63:19
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:147:5
    |
-LL |         let x = LoudDropper;
-   |             - these values have significant drop implementation and will observe changes in drop order under Edition 2024
-LL |         // Should lint
-LL |         x.get() + LoudDropper.get()
-   |                   ^^^^^^^^^^^
+LL |     let future = f();
+   |         ------
+   |         |
+   |         `future` calls a custom destructor
+   |         `future` will be dropped later as of Edition 2024
+...
+LL |     LoudDropper.get()
+   |     ^^^^^^^^^^^
+   |     |
+   |     this value will be stored in a temporary; let us call it `#1`
+   |     up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `future` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:164:14
+   |
+LL |     let x = T::default();
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     extract(&T::default())
+   |              ^^^^^^^^^^^^
+   |              |
+   |              this value will be stored in a temporary; let us call it `#1`
+   |              up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:178:5
+   |
+LL |     let x: Result<LoudDropper, ()> = Ok(LoudDropper);
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     LoudDropper.get()
+   |     ^^^^^^^^^^^
+   |     |
+   |     this value will be stored in a temporary; let us call it `#1`
+   |     up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:222:5
+   |
+LL |     let x = LoudDropper2;
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     LoudDropper3.get()
+   |     ^^^^^^^^^^^^
+   |     |
+   |     this value will be stored in a temporary; let us call it `#1`
+   |     up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:195:5
+   |
+LL | /     impl Drop for LoudDropper3 {
+LL | |
+LL | |         fn drop(&mut self) {
+LL | |             println!("loud drop");
+LL | |         }
+LL | |     }
+   | |_____^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:207:5
+   |
+LL | /     impl Drop for LoudDropper2 {
+LL | |
+LL | |         fn drop(&mut self) {
+LL | |             println!("loud drop");
+LL | |         }
+LL | |     }
+   | |_____^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:235:13
+   |
+LL |             LoudDropper.get()
+   |             ^^^^^^^^^^^
+   |             |
+   |             this value will be stored in a temporary; let us call it `#1`
+   |             up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL |             let _x = LoudDropper;
+   |                 --
+   |                 |
+   |                 `_x` calls a custom destructor
+   |                 `_x` will be dropped later as of Edition 2024
+...
+LL |     ));
+   |       - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `_x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
-error: aborting due to 3 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs
new file mode 100644
index 00000000000..9bffd6c6725
--- /dev/null
+++ b/tests/ui/dyn-star/async-block-dyn-star.rs
@@ -0,0 +1,9 @@
+//@ edition:2018
+
+#![feature(dyn_star, const_async_blocks)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+static S: dyn* Send + Sync = async { 42 };
+//~^ needs to have the same ABI as a pointer
+
+pub fn main() {}
diff --git a/tests/ui/dyn-star/async-block-dyn-star.stderr b/tests/ui/dyn-star/async-block-dyn-star.stderr
new file mode 100644
index 00000000000..f62c85c0ad2
--- /dev/null
+++ b/tests/ui/dyn-star/async-block-dyn-star.stderr
@@ -0,0 +1,20 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/async-block-dyn-star.rs:3:12
+   |
+LL | #![feature(dyn_star, const_async_blocks)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer
+  --> $DIR/async-block-dyn-star.rs:6:30
+   |
+LL | static S: dyn* Send + Sync = async { 42 };
+   |                              ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
index 7b5ea7bb707..a0aff69f396 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
@@ -1,14 +1,17 @@
 error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
    |
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
+   |                - this type parameter needs to be `Sized`
 LL |     dyn_debug(t);
    |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerLike` is not implemented for `&T`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   = note: required for `&T` to implement `PointerLike`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
+LL + fn polymorphic<T: Debug>(t: &T) {
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
-   |                                          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
index 7b5ea7bb707..a0aff69f396 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
@@ -1,14 +1,17 @@
 error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
    |
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
+   |                - this type parameter needs to be `Sized`
 LL |     dyn_debug(t);
    |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerLike` is not implemented for `&T`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   = note: required for `&T` to implement `PointerLike`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
+LL + fn polymorphic<T: Debug>(t: &T) {
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
-   |                                          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-star/drop.rs b/tests/ui/dyn-star/drop.rs
index ca86f1b5b01..bc746331527 100644
--- a/tests/ui/dyn-star/drop.rs
+++ b/tests/ui/dyn-star/drop.rs
@@ -1,13 +1,18 @@
 //@ run-pass
 //@ check-run-results
-#![feature(dyn_star)]
+#![feature(dyn_star, pointer_like_trait)]
 #![allow(incomplete_features)]
 
 use std::fmt::Debug;
+use std::marker::PointerLike;
 
 #[derive(Debug)]
+#[repr(transparent)]
 struct Foo(#[allow(dead_code)] usize);
 
+// FIXME(dyn_star): Make this into a derive.
+impl PointerLike for Foo {}
+
 impl Drop for Foo {
     fn drop(&mut self) {
         println!("destructor called");
diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs
index 6e895e9527a..3cc7390eb12 100644
--- a/tests/ui/dyn-star/enum-cast.rs
+++ b/tests/ui/dyn-star/enum-cast.rs
@@ -3,13 +3,18 @@
 // This used to ICE, because the compiler confused a pointer-like to dyn* coercion
 // with a c-like enum to integer cast.
 
-#![feature(dyn_star)]
+#![feature(dyn_star, pointer_like_trait)]
 #![expect(incomplete_features)]
 
+use std::marker::PointerLike;
+
+#[repr(transparent)]
 enum E {
     Num(usize),
 }
 
+impl PointerLike for E {}
+
 trait Trait {}
 impl Trait for E {}
 
diff --git a/tests/ui/dyn-star/error.rs b/tests/ui/dyn-star/error.rs
index d8261387efa..7288596f3fa 100644
--- a/tests/ui/dyn-star/error.rs
+++ b/tests/ui/dyn-star/error.rs
@@ -7,7 +7,7 @@ trait Foo {}
 
 fn make_dyn_star() {
     let i = 42;
-    let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied
+    let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr
index a9f4a054519..55981c03bac 100644
--- a/tests/ui/dyn-star/error.stderr
+++ b/tests/ui/dyn-star/error.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `{integer}: Foo` is not satisfied
+error[E0277]: the trait bound `usize: Foo` is not satisfied
   --> $DIR/error.rs:10:27
    |
 LL |     let dyn_i: dyn* Foo = i;
-   |                           ^ the trait `Foo` is not implemented for `{integer}`
+   |                           ^ the trait `Foo` is not implemented for `usize`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/error.rs:6:1
diff --git a/tests/ui/dyn-star/float-as-dyn-star.rs b/tests/ui/dyn-star/float-as-dyn-star.rs
new file mode 100644
index 00000000000..1b629c64c25
--- /dev/null
+++ b/tests/ui/dyn-star/float-as-dyn-star.rs
@@ -0,0 +1,16 @@
+//@ only-x86_64
+
+#![feature(dyn_star, pointer_like_trait)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+use std::fmt::Debug;
+use std::marker::PointerLike;
+
+fn make_dyn_star() -> dyn* Debug + 'static {
+    f32::from_bits(0x1) as f64
+    //~^ ERROR `f64` needs to have the same ABI as a pointer
+}
+
+fn main() {
+    println!("{:?}", make_dyn_star());
+}
diff --git a/tests/ui/dyn-star/float-as-dyn-star.stderr b/tests/ui/dyn-star/float-as-dyn-star.stderr
new file mode 100644
index 00000000000..9caba512e5f
--- /dev/null
+++ b/tests/ui/dyn-star/float-as-dyn-star.stderr
@@ -0,0 +1,21 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/float-as-dyn-star.rs:3:12
+   |
+LL | #![feature(dyn_star, pointer_like_trait)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `f64` needs to have the same ABI as a pointer
+  --> $DIR/float-as-dyn-star.rs:10:5
+   |
+LL |     f32::from_bits(0x1) as f64
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `f64`
+   = help: the trait `PointerLike` is implemented for `usize`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr
index adef9525bf1..801e1c233c1 100644
--- a/tests/ui/dyn-star/upcast.stderr
+++ b/tests/ui/dyn-star/upcast.stderr
@@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)]
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
+error[E0277]: `W` needs to have the same ABI as a pointer
+  --> $DIR/upcast.rs:28:23
+   |
+LL |     let w: dyn* Foo = W(0);
+   |                       ^^^^ `W` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `W`
+
 error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer
   --> $DIR/upcast.rs:30:23
    |
@@ -15,6 +23,6 @@ LL |     let w: dyn* Bar = w;
    |
    = help: the trait `PointerLike` is not implemented for `dyn* Foo`
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed
index 3fed16f0ee7..75bc598d17b 100644
--- a/tests/ui/editions/never-type-fallback-breaking.e2021.fixed
+++ b/tests/ui/editions/never-type-fallback-breaking.e2021.fixed
@@ -16,7 +16,7 @@ fn main() {
 
 fn m() {
     //[e2021]~^ this function depends on never type fallback being `()`
-    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     let x: () = match true {
         true => Default::default(),
         //[e2024]~^ error: the trait bound `!: Default` is not satisfied
@@ -28,7 +28,7 @@ fn m() {
 
 fn q() -> Option<()> {
     //[e2021]~^ this function depends on never type fallback being `()`
-    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     fn deserialize<T: Default>() -> Option<T> {
         Some(T::default())
     }
@@ -45,7 +45,7 @@ fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result<T, ()> {
 }
 fn meow() -> Result<(), ()> {
     //[e2021]~^ this function depends on never type fallback being `()`
-    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     help::<(), _>(1)?;
     //[e2024]~^ error: the trait bound `(): From<!>` is not satisfied
     Ok(())
diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
index fdc97e54d4e..454e88d4569 100644
--- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
+++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn m() {
    | ^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: Default` will fail
@@ -24,7 +24,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn q() -> Option<()> {
    | ^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: Default` will fail
@@ -43,7 +43,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn meow() -> Result<(), ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `(): From<!>` will fail
diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs
index 71d36f3a2d9..32e83e74139 100644
--- a/tests/ui/editions/never-type-fallback-breaking.rs
+++ b/tests/ui/editions/never-type-fallback-breaking.rs
@@ -16,7 +16,7 @@ fn main() {
 
 fn m() {
     //[e2021]~^ this function depends on never type fallback being `()`
-    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     let x = match true {
         true => Default::default(),
         //[e2024]~^ error: the trait bound `!: Default` is not satisfied
@@ -28,7 +28,7 @@ fn m() {
 
 fn q() -> Option<()> {
     //[e2021]~^ this function depends on never type fallback being `()`
-    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     fn deserialize<T: Default>() -> Option<T> {
         Some(T::default())
     }
@@ -45,7 +45,7 @@ fn help<'a: 'a, T: Into<()>, U>(_: U) -> Result<T, ()> {
 }
 fn meow() -> Result<(), ()> {
     //[e2021]~^ this function depends on never type fallback being `()`
-    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     help(1)?;
     //[e2024]~^ error: the trait bound `(): From<!>` is not satisfied
     Ok(())
diff --git a/tests/ui/explore-issue-38412.rs b/tests/ui/explore-issue-38412.rs
index e1295a96ba5..2008b120faa 100644
--- a/tests/ui/explore-issue-38412.rs
+++ b/tests/ui/explore-issue-38412.rs
@@ -1,9 +1,9 @@
 //@ aux-build:pub-and-stability.rs
 
-// A big point of this test is that we *declare* `unstable_declared`,
-// but do *not* declare `unstable_undeclared`. This way we can check
-// that the compiler is letting in uses of declared feature-gated
-// stuff but still rejecting uses of undeclared feature-gated stuff.
+// A big point of this test is that we *enable* `unstable_declared`,
+// but do *not* enable `unstable_undeclared`. This way we can check
+// that the compiler is letting in uses of enabled feature-gated
+// stuff but still rejecting uses of disabled feature-gated stuff.
 #![feature(unstable_declared)]
 
 extern crate pub_and_stability;
diff --git a/tests/ui/feature-gates/feature-gate-large-assignments.rs b/tests/ui/feature-gates/feature-gate-large-assignments.rs
index 7e9e574bfa0..c4125c55722 100644
--- a/tests/ui/feature-gates/feature-gate-large-assignments.rs
+++ b/tests/ui/feature-gates/feature-gate-large-assignments.rs
@@ -1,4 +1,4 @@
-// check that `move_size_limit is feature-gated
+// check that `move_size_limit` is feature-gated
 
 #![move_size_limit = "42"] //~ ERROR the `#[move_size_limit]` attribute is an experimental feature
 
diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.stderr b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_attr.stderr
index 8cbad78478e..3ea8c89bf3a 100644
--- a/tests/ui/feature-gates/feature-gate-link-arg-attribute.stderr
+++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_attr.stderr
@@ -1,5 +1,5 @@
 error[E0658]: link kind `link-arg` is unstable
-  --> $DIR/feature-gate-link-arg-attribute.rs:1:15
+  --> $DIR/feature-gate-link-arg-attribute.rs:5:15
    |
 LL | #[link(kind = "link-arg", name = "foo")]
    |               ^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr
new file mode 100644
index 00000000000..4d65db3c66d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.in_flag.stderr
@@ -0,0 +1,2 @@
+error: unknown linking modifier `link-arg`, expected one of: bundle, verbatim, whole-archive, as-needed
+
diff --git a/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs b/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs
index 9036095fbc4..c12ff5b04dc 100644
--- a/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs
+++ b/tests/ui/feature-gates/feature-gate-link-arg-attribute.rs
@@ -1,5 +1,9 @@
+//@ revisions: in_attr in_flag
+//@[in_flag] compile-flags: -l dylib:+link-arg=foo
+
+#[cfg(in_attr)]
 #[link(kind = "link-arg", name = "foo")]
-//~^ ERROR link kind `link-arg` is unstable
+//[in_attr]~^ ERROR link kind `link-arg` is unstable
 extern "C" {}
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs b/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs
new file mode 100644
index 00000000000..171509876d1
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-min-generic-const-args.rs
@@ -0,0 +1,11 @@
+trait Trait {
+    const ASSOC: usize;
+}
+
+// FIXME(min_generic_const_args): implement support for this, behind the feature gate
+fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
+    //~^ ERROR generic parameters may not be used in const operations
+    loop {}
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr b/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr
new file mode 100644
index 00000000000..04d96b4c11e
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr
@@ -0,0 +1,11 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/feature-gate-min-generic-const-args.rs:6:29
+   |
+LL | fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
+   |                             ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_attr.stderr
index 216477828e7..11b7abc883e 100644
--- a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr
+++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_attr.stderr
@@ -1,5 +1,5 @@
 error[E0658]: linking modifier `as-needed` is unstable
-  --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:50
+  --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:5:50
    |
 LL | #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")]
    |                                                  ^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr
new file mode 100644
index 00000000000..8f74e9d6f16
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.in_flag.stderr
@@ -0,0 +1,2 @@
+error: linking modifier `as-needed` is unstable, the `-Z unstable-options` flag must also be passed to use it
+
diff --git a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
index 132bc6ab04a..c2965e42f27 100644
--- a/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
+++ b/tests/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
@@ -1,5 +1,9 @@
+//@ revisions: in_attr in_flag
+//@[in_flag] compile-flags: -l dylib:+as-needed=foo
+
+#[cfg(in_attr)]
 #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")]
-//~^ ERROR: linking modifier `as-needed` is unstable
+//[in_attr]~^ ERROR: linking modifier `as-needed` is unstable
 extern "C" {}
 
 fn main() {}
diff --git a/tests/ui/generics/generics-on-self-mod-segment.rs b/tests/ui/generics/generics-on-self-mod-segment.rs
new file mode 100644
index 00000000000..ef229eeba53
--- /dev/null
+++ b/tests/ui/generics/generics-on-self-mod-segment.rs
@@ -0,0 +1,18 @@
+struct Ty;
+
+fn self_(_: self::<i32>::Ty) {}
+//~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment`
+
+fn crate_(_: crate::<i32>::Ty) {}
+//~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment`
+
+macro_rules! dollar_crate {
+    () => {
+        fn dollar_crate_(_: $crate::<i32>::Ty) {}
+        //~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment`
+    }
+}
+
+dollar_crate!();
+
+fn main() {}
diff --git a/tests/ui/generics/generics-on-self-mod-segment.stderr b/tests/ui/generics/generics-on-self-mod-segment.stderr
new file mode 100644
index 00000000000..4a2d5939a3e
--- /dev/null
+++ b/tests/ui/generics/generics-on-self-mod-segment.stderr
@@ -0,0 +1,32 @@
+error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment`
+  --> $DIR/generics-on-self-mod-segment.rs:3:20
+   |
+LL | fn self_(_: self::<i32>::Ty) {}
+   |             ----   ^^^ type argument not allowed
+   |             |
+   |             not allowed on module `generics_on_self_mod_segment`
+
+error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment`
+  --> $DIR/generics-on-self-mod-segment.rs:6:22
+   |
+LL | fn crate_(_: crate::<i32>::Ty) {}
+   |              -----   ^^^ type argument not allowed
+   |              |
+   |              not allowed on module `generics_on_self_mod_segment`
+
+error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment`
+  --> $DIR/generics-on-self-mod-segment.rs:11:38
+   |
+LL |         fn dollar_crate_(_: $crate::<i32>::Ty) {}
+   |                             ------   ^^^ type argument not allowed
+   |                             |
+   |                             not allowed on module `generics_on_self_mod_segment`
+...
+LL | dollar_crate!();
+   | --------------- in this macro invocation
+   |
+   = note: this error originates in the macro `dollar_crate` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0109`.
diff --git a/tests/ui/impl-trait/in-trait/refine-captures.rs b/tests/ui/impl-trait/in-trait/refine-captures.rs
new file mode 100644
index 00000000000..e7dffcb52aa
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/refine-captures.rs
@@ -0,0 +1,36 @@
+#![feature(precise_capturing_in_traits)]
+
+trait LifetimeParam<'a> {
+    fn test() -> impl Sized;
+}
+// Refining via capturing fewer lifetimes than the trait definition.
+impl<'a> LifetimeParam<'a> for i32 {
+    fn test() -> impl Sized + use<> {}
+    //~^ WARN impl trait in impl method captures fewer lifetimes than in trait
+}
+// If the lifetime is substituted, then we don't refine anything.
+impl LifetimeParam<'static> for u32 {
+    fn test() -> impl Sized + use<> {}
+    // Ok
+}
+
+trait TypeParam<T> {
+    fn test() -> impl Sized;
+}
+// Indirectly capturing a lifetime param through a type param substitution.
+impl<'a> TypeParam<&'a ()> for i32 {
+    fn test() -> impl Sized + use<> {}
+    //~^ WARN impl trait in impl method captures fewer lifetimes than in trait
+}
+// Two of them, but only one is captured...
+impl<'a, 'b> TypeParam<(&'a (), &'b ())> for u32 {
+    fn test() -> impl Sized + use<'b> {}
+    //~^ WARN impl trait in impl method captures fewer lifetimes than in trait
+}
+// What if we don't capture a type param? That should be an error otherwise.
+impl<T> TypeParam<T> for u64 {
+    fn test() -> impl Sized + use<> {}
+    //~^ ERROR `impl Trait` must mention all type parameters in scope in `use<...>`
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/refine-captures.stderr b/tests/ui/impl-trait/in-trait/refine-captures.stderr
new file mode 100644
index 00000000000..ad2c2a11601
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/refine-captures.stderr
@@ -0,0 +1,52 @@
+warning: impl trait in impl method captures fewer lifetimes than in trait
+  --> $DIR/refine-captures.rs:8:31
+   |
+LL |     fn test() -> impl Sized + use<> {}
+   |                               ^^^^^
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+   = note: `#[warn(refining_impl_trait_internal)]` on by default
+help: modify the `use<..>` bound to capture the same lifetimes that the trait does
+   |
+LL |     fn test() -> impl Sized + use<'a> {}
+   |                               ~~~~~~~
+
+warning: impl trait in impl method captures fewer lifetimes than in trait
+  --> $DIR/refine-captures.rs:22:31
+   |
+LL |     fn test() -> impl Sized + use<> {}
+   |                               ^^^^^
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+help: modify the `use<..>` bound to capture the same lifetimes that the trait does
+   |
+LL |     fn test() -> impl Sized + use<'a> {}
+   |                               ~~~~~~~
+
+warning: impl trait in impl method captures fewer lifetimes than in trait
+  --> $DIR/refine-captures.rs:27:31
+   |
+LL |     fn test() -> impl Sized + use<'b> {}
+   |                               ^^^^^^^
+   |
+   = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+   = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+help: modify the `use<..>` bound to capture the same lifetimes that the trait does
+   |
+LL |     fn test() -> impl Sized + use<'a, 'b> {}
+   |                               ~~~~~~~~~~~
+
+error: `impl Trait` must mention all type parameters in scope in `use<...>`
+  --> $DIR/refine-captures.rs:32:18
+   |
+LL | impl<T> TypeParam<T> for u64 {
+   |      - type parameter is implicitly captured by this `impl Trait`
+LL |     fn test() -> impl Sized + use<> {}
+   |                  ^^^^^^^^^^^^^^^^^^
+   |
+   = note: currently, all type parameters are required to be mentioned in the precise captures list
+
+error: aborting due to 1 previous error; 3 warnings emitted
+
diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs
new file mode 100644
index 00000000000..2efdc2342c1
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-macro.rs
@@ -0,0 +1,20 @@
+// A macro_rules macro in 2015 that has an RPIT without `use<>` that would
+// cause a problem with 2024 capturing rules.
+
+#[macro_export]
+macro_rules! macro_rpit {
+    () => {
+        fn test_mbe(x: &Vec<i32>) -> impl std::fmt::Display {
+            x[0]
+        }
+
+        pub fn from_mbe() {
+            let mut x = vec![];
+            x.push(1);
+
+            let element = test_mbe(&x);
+            x.push(2);
+            println!("{element}");
+        }
+    };
+}
diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs
new file mode 100644
index 00000000000..e197dcfef80
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/auxiliary/no-use-pm.rs
@@ -0,0 +1,29 @@
+// A proc-macro in 2015 that has an RPIT without `use<>` that would cause a
+// problem with 2024 capturing rules.
+
+//@ force-host
+//@ no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn pm_rpit(input: TokenStream) -> TokenStream {
+    "fn test_pm(x: &Vec<i32>) -> impl std::fmt::Display {
+    x[0]
+}
+
+pub fn from_pm() {
+    let mut x = vec![];
+    x.push(1);
+
+    let element = test_pm(&x);
+    x.push(2);
+    println!(\"{element}\");
+}
+"
+    .parse()
+    .unwrap()
+}
diff --git a/tests/ui/impl-trait/precise-capturing/external-macro.rs b/tests/ui/impl-trait/precise-capturing/external-macro.rs
new file mode 100644
index 00000000000..492e8036461
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/external-macro.rs
@@ -0,0 +1,26 @@
+// Tests that code generated from an external macro (MBE and proc-macro) that
+// has an RPIT will not fail when the call-site is 2024.
+// https://github.com/rust-lang/rust/issues/132917
+
+//@ aux-crate: no_use_pm=no-use-pm.rs
+//@ aux-crate: no_use_macro=no-use-macro.rs
+//@ edition: 2024
+//@ compile-flags:-Z unstable-options
+//@ check-pass
+
+no_use_pm::pm_rpit!{}
+
+no_use_macro::macro_rpit!{}
+
+fn main() {
+    let mut x = vec![];
+    x.push(1);
+
+    let element = test_pm(&x);
+    x.push(2);
+    println!("{element}");
+
+    let element = test_mbe(&x);
+    x.push(2);
+    println!("{element}");
+}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
index 6a9d72d028c..1eb88c71d54 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
@@ -1,4 +1,5 @@
 //@ run-rustfix
+//@ edition: 2018
 
 #![allow(unused)]
 #![deny(impl_trait_overcaptures)]
@@ -37,4 +38,8 @@ fn apit2<U, T: Sized>(_: &T, _: U) -> impl Sized + use<U, T> {}
 //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
 //~| WARN this changes meaning in Rust 2024
 
+async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {}
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+//~| WARN this changes meaning in Rust 2024
+
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
index 3a4f5ebb7fb..6f1ef6a472f 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
@@ -1,4 +1,5 @@
 //@ run-rustfix
+//@ edition: 2018
 
 #![allow(unused)]
 #![deny(impl_trait_overcaptures)]
@@ -37,4 +38,8 @@ fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
 //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
 //~| WARN this changes meaning in Rust 2024
 
+async fn async_fn<'a>(x: &'a ()) -> impl Sized {}
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+//~| WARN this changes meaning in Rust 2024
+
 fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
index c101b980c71..63c87cd46c8 100644
--- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
@@ -1,5 +1,5 @@
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
-  --> $DIR/overcaptures-2024.rs:6:29
+  --> $DIR/overcaptures-2024.rs:7:29
    |
 LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
    |                             ^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
 note: specifically, this lifetime is in scope but not mentioned in the type's bounds
-  --> $DIR/overcaptures-2024.rs:6:10
+  --> $DIR/overcaptures-2024.rs:7:10
    |
 LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
    |          ^^
    = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
 note: the lint level is defined here
-  --> $DIR/overcaptures-2024.rs:4:9
+  --> $DIR/overcaptures-2024.rs:5:9
    |
 LL | #![deny(impl_trait_overcaptures)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x }
    |                                        +++++++
 
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
-  --> $DIR/overcaptures-2024.rs:10:25
+  --> $DIR/overcaptures-2024.rs:11:25
    |
 LL | fn implicit(x: &i32) -> impl Sized { *x }
    |                         ^^^^^^^^^^
@@ -31,7 +31,7 @@ LL | fn implicit(x: &i32) -> impl Sized { *x }
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
 note: specifically, this lifetime is in scope but not mentioned in the type's bounds
-  --> $DIR/overcaptures-2024.rs:10:16
+  --> $DIR/overcaptures-2024.rs:11:16
    |
 LL | fn implicit(x: &i32) -> impl Sized { *x }
    |                ^
@@ -42,7 +42,7 @@ LL | fn implicit(x: &i32) -> impl Sized + use<> { *x }
    |                                    +++++++
 
 error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
-  --> $DIR/overcaptures-2024.rs:16:33
+  --> $DIR/overcaptures-2024.rs:17:33
    |
 LL |     fn hello(&self, x: &i32) -> impl Sized + '_ { self }
    |                                 ^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |     fn hello(&self, x: &i32) -> impl Sized + '_ { self }
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
 note: specifically, this lifetime is in scope but not mentioned in the type's bounds
-  --> $DIR/overcaptures-2024.rs:16:24
+  --> $DIR/overcaptures-2024.rs:17:24
    |
 LL |     fn hello(&self, x: &i32) -> impl Sized + '_ { self }
    |                        ^
@@ -61,7 +61,7 @@ LL |     fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self }
    |                                                 +++++++++
 
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
-  --> $DIR/overcaptures-2024.rs:28:47
+  --> $DIR/overcaptures-2024.rs:29:47
    |
 LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
    |                                               ^^^^^^^^^^
@@ -69,7 +69,7 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
 note: specifically, this lifetime is in scope but not mentioned in the type's bounds
-  --> $DIR/overcaptures-2024.rs:28:23
+  --> $DIR/overcaptures-2024.rs:29:23
    |
 LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
    |                       ^^
@@ -80,7 +80,7 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {}
    |                                                          +++++++
 
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
-  --> $DIR/overcaptures-2024.rs:32:28
+  --> $DIR/overcaptures-2024.rs:33:28
    |
 LL | fn apit(_: &impl Sized) -> impl Sized {}
    |                            ^^^^^^^^^^
@@ -88,13 +88,13 @@ LL | fn apit(_: &impl Sized) -> impl Sized {}
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
 note: specifically, this lifetime is in scope but not mentioned in the type's bounds
-  --> $DIR/overcaptures-2024.rs:32:12
+  --> $DIR/overcaptures-2024.rs:33:12
    |
 LL | fn apit(_: &impl Sized) -> impl Sized {}
    |            ^
    = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
-  --> $DIR/overcaptures-2024.rs:32:13
+  --> $DIR/overcaptures-2024.rs:33:13
    |
 LL | fn apit(_: &impl Sized) -> impl Sized {}
    |             ^^^^^^^^^^
@@ -104,7 +104,7 @@ LL | fn apit<T: Sized>(_: &T) -> impl Sized + use<T> {}
    |        ++++++++++     ~                ++++++++
 
 error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
-  --> $DIR/overcaptures-2024.rs:36:38
+  --> $DIR/overcaptures-2024.rs:37:38
    |
 LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
    |                                      ^^^^^^^^^^
@@ -112,13 +112,13 @@ LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
 note: specifically, this lifetime is in scope but not mentioned in the type's bounds
-  --> $DIR/overcaptures-2024.rs:36:16
+  --> $DIR/overcaptures-2024.rs:37:16
    |
 LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
    |                ^
    = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
-  --> $DIR/overcaptures-2024.rs:36:17
+  --> $DIR/overcaptures-2024.rs:37:17
    |
 LL | fn apit2<U>(_: &impl Sized, _: U) -> impl Sized {}
    |                 ^^^^^^^^^^
@@ -127,5 +127,24 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit
 LL | fn apit2<U, T: Sized>(_: &T, _: U) -> impl Sized + use<U, T> {}
    |           ++++++++++      ~                      +++++++++++
 
-error: aborting due to 6 previous errors
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+  --> $DIR/overcaptures-2024.rs:41:37
+   |
+LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {}
+   |                                     ^^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html>
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+  --> $DIR/overcaptures-2024.rs:41:19
+   |
+LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {}
+   |                   ^^
+   = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+   |
+LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {}
+   |                                                +++++++
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/intrinsics/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs
index 6c52651f060..0d047ccf4a3 100644
--- a/tests/ui/intrinsics/reify-intrinsic.rs
+++ b/tests/ui/intrinsics/reify-intrinsic.rs
@@ -13,9 +13,9 @@ fn b() {
 }
 
 fn c() {
-    let _: [unsafe extern "rust-intrinsic" fn(bool) -> bool; 2] = [
-        std::intrinsics::likely, //~ ERROR cannot coerce
-        std::intrinsics::unlikely,
+    let _: [unsafe extern "rust-intrinsic" fn(f32) -> f32; 2] = [
+        std::intrinsics::floorf32, //~ ERROR cannot coerce
+        std::intrinsics::log2f32,
     ];
 }
 
diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr
index 7af17147f28..a456e81e762 100644
--- a/tests/ui/intrinsics/reify-intrinsic.stderr
+++ b/tests/ui/intrinsics/reify-intrinsic.stderr
@@ -18,11 +18,11 @@ LL |     let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize)
 error[E0308]: cannot coerce intrinsics to function pointers
   --> $DIR/reify-intrinsic.rs:17:9
    |
-LL |         std::intrinsics::likely,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
+LL |         std::intrinsics::floorf32,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
    |
    = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(_) -> _`
-                 found fn item `fn(_) -> _ {likely}`
+                 found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {floorf32}`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs
new file mode 100644
index 00000000000..8d854c6c237
--- /dev/null
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs
@@ -0,0 +1,31 @@
+//@ only-x86_64
+
+const fn foo<const U: i32>() -> i32 {
+    U
+}
+
+fn main() {
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ());
+    //~^ invalid argument to a legacy const generic
+
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ());
+    //~^ invalid argument to a legacy const generic
+
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>());
+    //~^ invalid argument to a legacy const generic
+
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>());
+    //~^ invalid argument to a legacy const generic
+
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {});
+    //~^ invalid argument to a legacy const generic
+
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, {
+        struct F();
+        //~^ invalid argument to a legacy const generic
+        1
+    });
+
+    std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ());
+    //~^ invalid argument to a legacy const generic
+}
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
new file mode 100644
index 00000000000..7e05ae4f20c
--- /dev/null
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
@@ -0,0 +1,82 @@
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:8:55
+   |
+LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ());
+   |                                                       ^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL |     std::arch::x86_64::_mm_blend_ps::<{ || () }>(loop {}, loop {});
+   |                                    +++++++++++++ ~~~~~~~~~~~~~~~~
+
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:11:59
+   |
+LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ());
+   |                                                           ^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL |     std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {});
+   |                                    +++++++++++++++++++ ~~~~~~~~~~~~~~~~
+
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:14:61
+   |
+LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>());
+   |                                                             ^^^^^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL |     std::arch::x86_64::_mm_blend_ps::<{ foo::<{ 1 + 2 }>() }>(loop {}, loop {});
+   |                                    ++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~
+
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:17:61
+   |
+LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>());
+   |                                                             ^
+   |
+help: try using a const generic argument instead
+   |
+LL |     std::arch::x86_64::_mm_blend_ps::<{ foo::<3>() }>(loop {}, loop {});
+   |                                    ++++++++++++++++++ ~~~~~~~~~~~~~~~~
+
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:20:56
+   |
+LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {});
+   |                                                        ^^^^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL |     std::arch::x86_64::_mm_blend_ps::<{ &const {} }>(loop {}, loop {});
+   |                                    +++++++++++++++++ ~~~~~~~~~~~~~~~~
+
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:24:9
+   |
+LL |         struct F();
+   |         ^^^^^^^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL ~     std::arch::x86_64::_mm_blend_ps::<{ {
+LL +     struct F();
+LL +     1
+LL ~ } }>(loop {}, loop {});
+   |
+
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:29:59
+   |
+LL |     std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ());
+   |                                                           ^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL |     std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {});
+   |                                        ++++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/issues/issue-39848.stderr b/tests/ui/issues/issue-39848.stderr
index a6c6c61f170..1ffed2d4a1d 100644
--- a/tests/ui/issues/issue-39848.stderr
+++ b/tests/ui/issues/issue-39848.stderr
@@ -16,10 +16,10 @@ LL |         if $tgt.has_$field() {}
 LL |     get_opt!(bar, foo);
    |     ------------------ in this macro invocation
    = note: this error originates in the macro `get_opt` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: try placing this code inside a block
+help: you might have meant to write a method call
    |
-LL |         if $tgt.has_{ $field() } {}
-   |                     +          +
+LL |         if $tgt.has_.$field() {}
+   |                     +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/let-else/let-else-if.stderr b/tests/ui/let-else/let-else-if.stderr
index 7e2215c8c05..ad36b423150 100644
--- a/tests/ui/let-else/let-else-if.stderr
+++ b/tests/ui/let-else/let-else-if.stderr
@@ -4,7 +4,7 @@ error: conditional `else if` is not supported for `let...else`
 LL |     let Some(_) = Some(()) else if true {
    |                                 ^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL ~     let Some(_) = Some(()) else { if true {
 LL |
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
index 2b515d3e6d5..17c3eca89e2 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
@@ -1,6 +1,7 @@
 #![deny(dangling_pointers_from_temporaries)]
+#![feature(sync_unsafe_cell)]
 
-use std::cell::Cell;
+use std::cell::{Cell, SyncUnsafeCell, UnsafeCell};
 use std::ffi::{CStr, CString};
 use std::mem::MaybeUninit;
 
@@ -47,6 +48,10 @@ fn main() {
     //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
     declval::<Vec<AsPtrFake>>().as_ptr();
     //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+    declval::<UnsafeCell<u8>>().get();
+    //~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped
+    declval::<SyncUnsafeCell<u8>>().get();
+    //~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped
     declval::<Box<AsPtrFake>>().as_ptr();
     declval::<AsPtrFake>().as_ptr();
 }
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
index c582a4c6540..250ed6dc9e3 100644
--- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
@@ -1,5 +1,5 @@
 error: a dangling pointer will be produced because the temporary `CString` will be dropped
-  --> $DIR/types.rs:20:26
+  --> $DIR/types.rs:21:26
    |
 LL |     declval::<CString>().as_ptr();
    |     -------------------- ^^^^^^ this pointer will immediately be invalid
@@ -15,7 +15,7 @@ LL | #![deny(dangling_pointers_from_temporaries)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a dangling pointer will be produced because the temporary `String` will be dropped
-  --> $DIR/types.rs:22:25
+  --> $DIR/types.rs:23:25
    |
 LL |     declval::<String>().as_ptr();
    |     ------------------- ^^^^^^ this pointer will immediately be invalid
@@ -26,7 +26,7 @@ LL |     declval::<String>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
-  --> $DIR/types.rs:24:26
+  --> $DIR/types.rs:25:26
    |
 LL |     declval::<Vec<u8>>().as_ptr();
    |     -------------------- ^^^^^^ this pointer will immediately be invalid
@@ -37,7 +37,7 @@ LL |     declval::<Vec<u8>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
-  --> $DIR/types.rs:26:31
+  --> $DIR/types.rs:27:31
    |
 LL |     declval::<Box<CString>>().as_ptr();
    |     ------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -48,7 +48,7 @@ LL |     declval::<Box<CString>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
-  --> $DIR/types.rs:28:28
+  --> $DIR/types.rs:29:28
    |
 LL |     declval::<Box<[u8]>>().as_ptr();
    |     ---------------------- ^^^^^^ this pointer will immediately be invalid
@@ -59,7 +59,7 @@ LL |     declval::<Box<[u8]>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
-  --> $DIR/types.rs:30:27
+  --> $DIR/types.rs:31:27
    |
 LL |     declval::<Box<str>>().as_ptr();
    |     --------------------- ^^^^^^ this pointer will immediately be invalid
@@ -70,7 +70,7 @@ LL |     declval::<Box<str>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
-  --> $DIR/types.rs:32:28
+  --> $DIR/types.rs:33:28
    |
 LL |     declval::<Box<CStr>>().as_ptr();
    |     ---------------------- ^^^^^^ this pointer will immediately be invalid
@@ -81,7 +81,7 @@ LL |     declval::<Box<CStr>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
-  --> $DIR/types.rs:34:27
+  --> $DIR/types.rs:35:27
    |
 LL |     declval::<[u8; 10]>().as_ptr();
    |     --------------------- ^^^^^^ this pointer will immediately be invalid
@@ -92,7 +92,7 @@ LL |     declval::<[u8; 10]>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
-  --> $DIR/types.rs:36:32
+  --> $DIR/types.rs:37:32
    |
 LL |     declval::<Box<[u8; 10]>>().as_ptr();
    |     -------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -103,7 +103,7 @@ LL |     declval::<Box<[u8; 10]>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
-  --> $DIR/types.rs:38:31
+  --> $DIR/types.rs:39:31
    |
 LL |     declval::<Box<Vec<u8>>>().as_ptr();
    |     ------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -114,7 +114,7 @@ LL |     declval::<Box<Vec<u8>>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
-  --> $DIR/types.rs:40:30
+  --> $DIR/types.rs:41:30
    |
 LL |     declval::<Box<String>>().as_ptr();
    |     ------------------------ ^^^^^^ this pointer will immediately be invalid
@@ -125,7 +125,7 @@ LL |     declval::<Box<String>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
-  --> $DIR/types.rs:42:43
+  --> $DIR/types.rs:43:43
    |
 LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
    |     ------------------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -136,7 +136,7 @@ LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
-  --> $DIR/types.rs:44:27
+  --> $DIR/types.rs:45:27
    |
 LL |     declval::<Cell<u8>>().as_ptr();
    |     --------------------- ^^^^^^ this pointer will immediately be invalid
@@ -147,7 +147,7 @@ LL |     declval::<Cell<u8>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
-  --> $DIR/types.rs:46:34
+  --> $DIR/types.rs:47:34
    |
 LL |     declval::<MaybeUninit<u8>>().as_ptr();
    |     ---------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -158,7 +158,7 @@ LL |     declval::<MaybeUninit<u8>>().as_ptr();
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
 error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
-  --> $DIR/types.rs:48:33
+  --> $DIR/types.rs:49:33
    |
 LL |     declval::<Vec<AsPtrFake>>().as_ptr();
    |     --------------------------- ^^^^^^ this pointer will immediately be invalid
@@ -168,5 +168,27 @@ LL |     declval::<Vec<AsPtrFake>>().as_ptr();
    = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
    = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 
-error: aborting due to 15 previous errors
+error: a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped
+  --> $DIR/types.rs:51:33
+   |
+LL |     declval::<UnsafeCell<u8>>().get();
+   |     --------------------------- ^^^ this pointer will immediately be invalid
+   |     |
+   |     this `UnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped
+  --> $DIR/types.rs:53:37
+   |
+LL |     declval::<SyncUnsafeCell<u8>>().get();
+   |     ------------------------------- ^^^ this pointer will immediately be invalid
+   |     |
+   |     this `SyncUnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/lint/issue-104392.stderr b/tests/ui/lint/issue-104392.stderr
index 8e466439ae6..4d8d8c56d41 100644
--- a/tests/ui/lint/issue-104392.stderr
+++ b/tests/ui/lint/issue-104392.stderr
@@ -6,7 +6,7 @@ LL |     { unsafe 92 }
    |       |
    |       while parsing this `unsafe` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     { unsafe { 92 } }
    |              +    +
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
index 7cf4aa6cdd4..ada37ccd640 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
@@ -10,7 +10,7 @@
     unused_mut,
     unused_variables
 )]
-#![deny(unused_parens)]
+#![deny(unused_parens, unused_braces)]
 
 fn lint_on_top_level() {
     let a = 0; //~ ERROR unnecessary parentheses around pattern
@@ -43,8 +43,10 @@ fn no_lint_ops() {
 fn lint_break_if_not_followed_by_block() {
     #![allow(unreachable_code)]
     loop { if break {} } //~ ERROR unnecessary parentheses
-    loop { if break ({ println!("hello") }) {} } //~ ERROR unnecessary parentheses
-    loop { if (break { println!("hello") }) {} }
+    loop { if break { println!("hello") } {} }
+    //~^ ERROR unnecessary parentheses around `if` condition
+    //~| ERROR unnecessary parentheses around `break` value
+    loop { if (break println!("hello")) {} } //~ ERROR unnecessary braces around `break` value
 }
 
 // Don't lint in these cases (#64106).
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
index 013255dc213..67066c3bee3 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
@@ -10,7 +10,7 @@
     unused_mut,
     unused_variables
 )]
-#![deny(unused_parens)]
+#![deny(unused_parens, unused_braces)]
 
 fn lint_on_top_level() {
     let (a) = 0; //~ ERROR unnecessary parentheses around pattern
@@ -43,8 +43,10 @@ fn no_lint_ops() {
 fn lint_break_if_not_followed_by_block() {
     #![allow(unreachable_code)]
     loop { if (break) {} } //~ ERROR unnecessary parentheses
-    loop { if (break ({ println!("hello") })) {} } //~ ERROR unnecessary parentheses
-    loop { if (break { println!("hello") }) {} }
+    loop { if (break ({ println!("hello") })) {} }
+    //~^ ERROR unnecessary parentheses around `if` condition
+    //~| ERROR unnecessary parentheses around `break` value
+    loop { if (break { println!("hello") }) {} } //~ ERROR unnecessary braces around `break` value
 }
 
 // Don't lint in these cases (#64106).
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
index f916bba8194..d5fdaef42d8 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
@@ -7,7 +7,7 @@ LL |     let (a) = 0;
 note: the lint level is defined here
   --> $DIR/issue-54538-unused-parens-lint.rs:13:9
    |
-LL | #![deny(unused_parens)]
+LL | #![deny(unused_parens, unused_braces)]
    |         ^^^^^^^^^^^^^
 help: remove these parentheses
    |
@@ -99,8 +99,37 @@ LL -     loop { if (break ({ println!("hello") })) {} }
 LL +     loop { if break ({ println!("hello") }) {} }
    |
 
+error: unnecessary parentheses around `break` value
+  --> $DIR/issue-54538-unused-parens-lint.rs:46:22
+   |
+LL |     loop { if (break ({ println!("hello") })) {} }
+   |                      ^                     ^
+   |
+help: remove these parentheses
+   |
+LL -     loop { if (break ({ println!("hello") })) {} }
+LL +     loop { if (break { println!("hello") }) {} }
+   |
+
+error: unnecessary braces around `break` value
+  --> $DIR/issue-54538-unused-parens-lint.rs:49:22
+   |
+LL |     loop { if (break { println!("hello") }) {} }
+   |                      ^^                 ^^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-54538-unused-parens-lint.rs:13:24
+   |
+LL | #![deny(unused_parens, unused_braces)]
+   |                        ^^^^^^^^^^^^^
+help: remove these braces
+   |
+LL -     loop { if (break { println!("hello") }) {} }
+LL +     loop { if (break println!("hello")) {} }
+   |
+
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:71:12
+  --> $DIR/issue-54538-unused-parens-lint.rs:73:12
    |
 LL |     if let (0 | 1) = 0 {}
    |            ^     ^
@@ -112,7 +141,7 @@ LL +     if let 0 | 1 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:72:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:74:13
    |
 LL |     if let ((0 | 1),) = (0,) {}
    |             ^     ^
@@ -124,7 +153,7 @@ LL +     if let (0 | 1,) = (0,) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:73:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:75:13
    |
 LL |     if let [(0 | 1)] = [0] {}
    |             ^     ^
@@ -136,7 +165,7 @@ LL +     if let [0 | 1] = [0] {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:74:16
+  --> $DIR/issue-54538-unused-parens-lint.rs:76:16
    |
 LL |     if let 0 | (1 | 2) = 0 {}
    |                ^     ^
@@ -148,7 +177,7 @@ LL +     if let 0 | 1 | 2 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:76:15
+  --> $DIR/issue-54538-unused-parens-lint.rs:78:15
    |
 LL |     if let TS((0 | 1)) = TS(0) {}
    |               ^     ^
@@ -160,7 +189,7 @@ LL +     if let TS(0 | 1) = TS(0) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:78:20
+  --> $DIR/issue-54538-unused-parens-lint.rs:80:20
    |
 LL |     if let NS { f: (0 | 1) } = (NS { f: 0 }) {}
    |                    ^     ^
@@ -172,7 +201,7 @@ LL +     if let NS { f: 0 | 1 } = (NS { f: 0 }) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:88:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:90:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -184,7 +213,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:89:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:91:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -196,7 +225,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:90:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:92:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -208,7 +237,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:91:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:93:9
    |
 LL |         (e @ 1...2) => {}
    |         ^         ^
@@ -220,7 +249,7 @@ LL +         e @ 1...2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:97:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:99:9
    |
 LL |         (e @ &(1...2)) => {}
    |         ^            ^
@@ -232,7 +261,7 @@ LL +         e @ &(1...2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:98:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:100:10
    |
 LL |         &(_) => {}
    |          ^ ^
@@ -244,7 +273,7 @@ LL +         &_ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:109:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:111:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -256,7 +285,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:110:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:112:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -268,7 +297,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:111:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:113:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -280,7 +309,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:112:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:114:9
    |
 LL |         (e @ 1..=2) => {}
    |         ^         ^
@@ -292,7 +321,7 @@ LL +         e @ 1..=2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:118:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:120:9
    |
 LL |         (e @ &(1..=2)) => {}
    |         ^            ^
@@ -304,7 +333,7 @@ LL +         e @ &(1..=2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:119:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:121:10
    |
 LL |         &(_) => {}
    |          ^ ^
@@ -315,5 +344,5 @@ LL -         &(_) => {}
 LL +         &_ => {}
    |
 
-error: aborting due to 26 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed
new file mode 100644
index 00000000000..9343d906cdc
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.fixed
@@ -0,0 +1,32 @@
+//@ run-rustfix
+#![deny(unused_parens)]
+#![allow(unreachable_code)]
+
+fn foo() {
+    loop {
+        break (_ = 42);
+        // lint unused_parens should not be triggered here.
+    }
+
+    let _ = loop {
+        let a = 1;
+        let b = 2;
+        break a + b; //~ERROR unnecessary parentheses
+    };
+
+    loop {
+        if break return () {
+            //~^ ERROR unnecessary parentheses
+        }
+        if break return () {
+            //~^ ERROR unnecessary parentheses
+        }
+    }
+
+    return (_ = 42);
+    // lint unused_parens should not be triggered here.
+}
+
+fn main() {
+    let _ = foo();
+}
diff --git a/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs
new file mode 100644
index 00000000000..fe9cba3e168
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.rs
@@ -0,0 +1,32 @@
+//@ run-rustfix
+#![deny(unused_parens)]
+#![allow(unreachable_code)]
+
+fn foo() {
+    loop {
+        break (_ = 42);
+        // lint unused_parens should not be triggered here.
+    }
+
+    let _ = loop {
+        let a = 1;
+        let b = 2;
+        break (a + b); //~ERROR unnecessary parentheses
+    };
+
+    loop {
+        if (break return ()) {
+            //~^ ERROR unnecessary parentheses
+        }
+        if break (return ()) {
+            //~^ ERROR unnecessary parentheses
+        }
+    }
+
+    return (_ = 42);
+    // lint unused_parens should not be triggered here.
+}
+
+fn main() {
+    let _ = foo();
+}
diff --git a/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr
new file mode 100644
index 00000000000..c41cf32bade
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-assign-expr-in-ret-issue-131989.stderr
@@ -0,0 +1,43 @@
+error: unnecessary parentheses around `break` value
+  --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:14:15
+   |
+LL |         break (a + b);
+   |               ^     ^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:2:9
+   |
+LL | #![deny(unused_parens)]
+   |         ^^^^^^^^^^^^^
+help: remove these parentheses
+   |
+LL -         break (a + b);
+LL +         break a + b;
+   |
+
+error: unnecessary parentheses around `if` condition
+  --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:18:12
+   |
+LL |         if (break return ()) {
+   |            ^               ^
+   |
+help: remove these parentheses
+   |
+LL -         if (break return ()) {
+LL +         if break return () {
+   |
+
+error: unnecessary parentheses around `break` value
+  --> $DIR/unused-parens-assign-expr-in-ret-issue-131989.rs:21:18
+   |
+LL |         if break (return ()) {
+   |                  ^         ^
+   |
+help: remove these parentheses
+   |
+LL -         if break (return ()) {
+LL +         if break return () {
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/lint/unused_parens_json_suggestion.fixed b/tests/ui/lint/unused_parens_json_suggestion.fixed
index 89fd0d86614..f26bedc3fd5 100644
--- a/tests/ui/lint/unused_parens_json_suggestion.fixed
+++ b/tests/ui/lint/unused_parens_json_suggestion.fixed
@@ -9,7 +9,7 @@
 // test of the JSON error format.
 
 #![deny(unused_parens)]
-#![allow(unreachable_code)]
+#![allow(unreachable_code, unused_braces)]
 
 fn main() {
     // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
diff --git a/tests/ui/lint/unused_parens_json_suggestion.rs b/tests/ui/lint/unused_parens_json_suggestion.rs
index 4526084196c..af3d88f71bb 100644
--- a/tests/ui/lint/unused_parens_json_suggestion.rs
+++ b/tests/ui/lint/unused_parens_json_suggestion.rs
@@ -9,7 +9,7 @@
 // test of the JSON error format.
 
 #![deny(unused_parens)]
-#![allow(unreachable_code)]
+#![allow(unreachable_code, unused_braces)]
 
 fn main() {
     // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
diff --git a/tests/ui/lint/unused_parens_json_suggestion.stderr b/tests/ui/lint/unused_parens_json_suggestion.stderr
index 1f4928cd464..2ce31817d29 100644
--- a/tests/ui/lint/unused_parens_json_suggestion.stderr
+++ b/tests/ui/lint/unused_parens_json_suggestion.stderr
@@ -1,4 +1,4 @@
-{"$message_type":"diagnostic","message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":633,"byte_end":634,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":633,"byte_end":634,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around assigned value
+{"$message_type":"diagnostic","message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":636,"byte_end":637,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":648,"byte_end":649,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":636,"byte_end":637,"line_start":17,"line_end":17,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":648,"byte_end":649,"line_start":17,"line_end":17,"column_start":26,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":26,"highlight_end":27}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around assigned value
   --> $DIR/unused_parens_json_suggestion.rs:17:14
    |
 LL |     let _a = (1 / (2 + 3));
diff --git a/tests/ui/lint/unused_parens_remove_json_suggestion.fixed b/tests/ui/lint/unused_parens_remove_json_suggestion.fixed
index e2774d5d7e5..899c24f83ed 100644
--- a/tests/ui/lint/unused_parens_remove_json_suggestion.fixed
+++ b/tests/ui/lint/unused_parens_remove_json_suggestion.fixed
@@ -9,7 +9,7 @@
 // test of the JSON error format.
 
 #![deny(unused_parens)]
-#![allow(unreachable_code)]
+#![allow(unreachable_code, unused_braces)]
 
 fn main() {
 
diff --git a/tests/ui/lint/unused_parens_remove_json_suggestion.rs b/tests/ui/lint/unused_parens_remove_json_suggestion.rs
index b3ac87178db..7f5d935c4ac 100644
--- a/tests/ui/lint/unused_parens_remove_json_suggestion.rs
+++ b/tests/ui/lint/unused_parens_remove_json_suggestion.rs
@@ -9,7 +9,7 @@
 // test of the JSON error format.
 
 #![deny(unused_parens)]
-#![allow(unreachable_code)]
+#![allow(unreachable_code, unused_braces)]
 
 fn main() {
 
diff --git a/tests/ui/lint/unused_parens_remove_json_suggestion.stderr b/tests/ui/lint/unused_parens_remove_json_suggestion.stderr
index 9268fc1abc4..975de4edfdf 100644
--- a/tests/ui/lint/unused_parens_remove_json_suggestion.stderr
+++ b/tests/ui/lint/unused_parens_remove_json_suggestion.stderr
@@ -1,4 +1,4 @@
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":525,"byte_end":526,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":528,"byte_end":529,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":525,"byte_end":526,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":528,"byte_end":529,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":540,"byte_end":541,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":543,"byte_end":544,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":439,"byte_end":452,"line_start":11,"line_end":11,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":540,"byte_end":541,"line_start":18,"line_end":18,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":543,"byte_end":544,"line_start":18,"line_end":18,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    if (_b) {","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:18:8
    |
 LL |     if (_b) {
@@ -16,7 +16,7 @@ LL +     if _b {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":622,"byte_end":623,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":624,"byte_end":625,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":622,"byte_end":623,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":624,"byte_end":625,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":637,"byte_end":638,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":639,"byte_end":640,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":637,"byte_end":638,"line_start":29,"line_end":29,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":7,"highlight_end":8}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":639,"byte_end":640,"line_start":29,"line_end":29,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    if(c) {","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:29:7
    |
 LL |     if(c) {
@@ -29,7 +29,7 @@ LL +     if c {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":668,"byte_end":669,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":670,"byte_end":671,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":668,"byte_end":669,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":670,"byte_end":671,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":683,"byte_end":684,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":685,"byte_end":686,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":683,"byte_end":684,"line_start":33,"line_end":33,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":8,"highlight_end":9}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":685,"byte_end":686,"line_start":33,"line_end":33,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    if (c){","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:33:8
    |
 LL |     if (c){
@@ -42,7 +42,7 @@ LL +     if c {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":716,"byte_end":717,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":730,"byte_end":731,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":716,"byte_end":717,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":730,"byte_end":731,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":731,"byte_end":732,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":745,"byte_end":746,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":731,"byte_end":732,"line_start":37,"line_end":37,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":745,"byte_end":746,"line_start":37,"line_end":37,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:37:11
    |
 LL |     while (false && true){
@@ -55,7 +55,7 @@ LL +     while false && true {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":744,"byte_end":745,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":746,"byte_end":747,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":744,"byte_end":745,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":746,"byte_end":747,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":759,"byte_end":760,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":761,"byte_end":762,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":759,"byte_end":760,"line_start":38,"line_end":38,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":12,"highlight_end":13}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":761,"byte_end":762,"line_start":38,"line_end":38,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"        if (c) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `if` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:38:12
    |
 LL |         if (c) {
@@ -68,7 +68,7 @@ LL +         if c {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":822,"byte_end":823,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":836,"byte_end":837,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":822,"byte_end":823,"line_start":44,"line_end":44,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":10,"highlight_end":11}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":836,"byte_end":837,"line_start":44,"line_end":44,"column_start":24,"column_end":25,"is_primary":true,"text":[{"text":"    while(true && false) {","highlight_start":24,"highlight_end":25}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:44:10
    |
 LL |     while(true && false) {
@@ -81,7 +81,7 @@ LL +     while true && false {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":842,"byte_end":843,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":849,"byte_end":850,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":842,"byte_end":843,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":849,"byte_end":850,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":857,"byte_end":858,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":864,"byte_end":865,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":857,"byte_end":858,"line_start":45,"line_end":45,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":18,"highlight_end":19}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":864,"byte_end":865,"line_start":45,"line_end":45,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression
   --> $DIR/unused_parens_remove_json_suggestion.rs:45:18
    |
 LL |         for _ in (0 .. 3){
@@ -94,7 +94,7 @@ LL +         for _ in 0 .. 3 {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":909,"byte_end":910,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":916,"byte_end":917,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":909,"byte_end":910,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":916,"byte_end":917,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":924,"byte_end":925,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":931,"byte_end":932,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":924,"byte_end":925,"line_start":50,"line_end":50,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":14,"highlight_end":15}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":931,"byte_end":932,"line_start":50,"line_end":50,"column_start":21,"column_end":22,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {","highlight_start":21,"highlight_end":22}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `for` iterator expression
   --> $DIR/unused_parens_remove_json_suggestion.rs:50:14
    |
 LL |     for _ in (0 .. 3) {
@@ -107,7 +107,7 @@ LL +     for _ in 0 .. 3 {
    |
 
 "}
-{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":934,"byte_end":935,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":948,"byte_end":949,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":934,"byte_end":935,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":948,"byte_end":949,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+{"$message_type":"diagnostic","message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":949,"byte_end":950,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":963,"byte_end":964,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":949,"byte_end":950,"line_start":51,"line_end":51,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":15,"highlight_end":16}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":963,"byte_end":964,"line_start":51,"line_end":51,"column_start":29,"column_end":30,"is_primary":true,"text":[{"text":"        while (true && false) {","highlight_start":29,"highlight_end":30}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:51:15
    |
 LL |         while (true && false) {
diff --git a/tests/ui/match/intended-binding-pattern-is-const.rs b/tests/ui/match/intended-binding-pattern-is-const.rs
new file mode 100644
index 00000000000..95c8119cdb9
--- /dev/null
+++ b/tests/ui/match/intended-binding-pattern-is-const.rs
@@ -0,0 +1,10 @@
+fn main() {
+    match 1 { //~ ERROR non-exhaustive patterns
+        //~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+        //~| the matched value is of type `i32`
+        x => {} //~ this pattern doesn't introduce a new catch-all binding
+        //~^ HELP ensure that all possible cases are being handled
+        //~| HELP if you meant to introduce a binding, use a different name
+    }
+    const x: i32 = 4; //~ NOTE constant `x` defined here
+}
diff --git a/tests/ui/match/intended-binding-pattern-is-const.stderr b/tests/ui/match/intended-binding-pattern-is-const.stderr
new file mode 100644
index 00000000000..99af1c7a16e
--- /dev/null
+++ b/tests/ui/match/intended-binding-pattern-is-const.stderr
@@ -0,0 +1,27 @@
+error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+  --> $DIR/intended-binding-pattern-is-const.rs:2:11
+   |
+LL |     match 1 {
+   |           ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+...
+LL |         x => {}
+   |         - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
+   |
+   = note: the matched value is of type `i32`
+note: constant `x` defined here
+  --> $DIR/intended-binding-pattern-is-const.rs:9:5
+   |
+LL |     const x: i32 = 4;
+   |     ^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         x_var => {}
+   |          ++++
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL |         x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
+   |                ++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr
index f5b79602797..adb662c98a7 100644
--- a/tests/ui/mir/issue-112269.stderr
+++ b/tests/ui/mir/issue-112269.stderr
@@ -1,30 +1,34 @@
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:3:9
    |
+LL |     const x: i32 = 4;
+   |     ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
 LL |     let x: i32 = 3;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `x_var`
+   |         ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let x_var: i32 = 3;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:7:9
    |
+LL |     const y: i32 = 3;
+   |     ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
 LL |     let y = 4;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `y_var`
+   |         ^ patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let y_var = 4;
+   |         ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/missing/missing-block-hint.stderr b/tests/ui/missing/missing-block-hint.stderr
index 18719289abd..7a08d70d0ce 100644
--- a/tests/ui/missing/missing-block-hint.stderr
+++ b/tests/ui/missing/missing-block-hint.stderr
@@ -25,7 +25,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |         if (foo)
    |            ^^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |             { bar; }
    |             +      +
diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.fixed b/tests/ui/moves/moved-value-on-as-ref-arg.fixed
index 292fa98a3f7..97bfe094ce5 100644
--- a/tests/ui/moves/moved-value-on-as-ref-arg.fixed
+++ b/tests/ui/moves/moved-value-on-as-ref-arg.fixed
@@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
 
 fn foo<T: AsRef<Bar>>(_: T) {}
 fn qux<T: AsMut<Bar>>(_: T) {}
-fn bat<T: Borrow<T>>(_: T) {}
-fn baz<T: BorrowMut<T>>(_: T) {}
+fn bat<T: Borrow<Bar>>(_: T) {}
+fn baz<T: BorrowMut<Bar>>(_: T) {}
 
 pub fn main() {
     let bar = Bar;
diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.rs b/tests/ui/moves/moved-value-on-as-ref-arg.rs
index 632af9efcda..fed41cf710d 100644
--- a/tests/ui/moves/moved-value-on-as-ref-arg.rs
+++ b/tests/ui/moves/moved-value-on-as-ref-arg.rs
@@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
 
 fn foo<T: AsRef<Bar>>(_: T) {}
 fn qux<T: AsMut<Bar>>(_: T) {}
-fn bat<T: Borrow<T>>(_: T) {}
-fn baz<T: BorrowMut<T>>(_: T) {}
+fn bat<T: Borrow<Bar>>(_: T) {}
+fn baz<T: BorrowMut<Bar>>(_: T) {}
 
 pub fn main() {
     let bar = Bar;
diff --git a/tests/ui/moves/region-var-in-moved-ty-issue-133118.rs b/tests/ui/moves/region-var-in-moved-ty-issue-133118.rs
new file mode 100644
index 00000000000..a49370e315d
--- /dev/null
+++ b/tests/ui/moves/region-var-in-moved-ty-issue-133118.rs
@@ -0,0 +1,25 @@
+//! regression test for #133118
+
+pub trait Alpha {
+    fn y(self) -> usize;
+}
+
+pub trait Beta {
+    type Gamma;
+    fn gamma(&self) -> Self::Gamma;
+}
+
+pub fn a<T: Alpha>(_x: T) -> usize {
+    todo!();
+}
+
+pub fn x<B>(beta: &B) -> usize
+where
+    for<'a> &'a B: Beta,
+    for<'a> <&'a B as Beta>::Gamma: Alpha,
+{
+    let g1 = beta.gamma();
+    a(g1) + a(g1) //~ ERROR use of moved value: `g1` [E0382]
+}
+
+pub fn main() {}
diff --git a/tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr b/tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr
new file mode 100644
index 00000000000..691625d042d
--- /dev/null
+++ b/tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr
@@ -0,0 +1,21 @@
+error[E0382]: use of moved value: `g1`
+  --> $DIR/region-var-in-moved-ty-issue-133118.rs:22:15
+   |
+LL |     let g1 = beta.gamma();
+   |         -- move occurs because `g1` has type `<&B as Beta>::Gamma`, which does not implement the `Copy` trait
+LL |     a(g1) + a(g1)
+   |       --      ^^ value used here after move
+   |       |
+   |       value moved here
+   |
+note: consider changing this parameter type in function `a` to borrow instead if owning the value isn't necessary
+  --> $DIR/region-var-in-moved-ty-issue-133118.rs:12:24
+   |
+LL | pub fn a<T: Alpha>(_x: T) -> usize {
+   |        -               ^ this parameter takes ownership of the value
+   |        |
+   |        in this function
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr b/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr
new file mode 100644
index 00000000000..ea36af0b4cf
--- /dev/null
+++ b/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr
@@ -0,0 +1,2 @@
+error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr b/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr
new file mode 100644
index 00000000000..ea36af0b4cf
--- /dev/null
+++ b/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr
@@ -0,0 +1,2 @@
+error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr b/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr
new file mode 100644
index 00000000000..1e701374688
--- /dev/null
+++ b/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr
@@ -0,0 +1,2 @@
+error: unknown linking modifier ``, expected one of: bundle, verbatim, whole-archive, as-needed
+
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.rs b/tests/ui/native-library-link-flags/modifiers-bad.rs
new file mode 100644
index 00000000000..185201e0d84
--- /dev/null
+++ b/tests/ui/native-library-link-flags/modifiers-bad.rs
@@ -0,0 +1,11 @@
+//@ edition: 2021
+//@ revisions: blank no-prefix prefix-only unknown
+
+//@[blank] compile-flags: -l static:=foo
+//@[no-prefix] compile-flags: -l static:bundle=foo
+//@[prefix-only] compile-flags: -l static:+=foo
+//@[unknown] compile-flags: -l static:+ferris=foo
+
+// Tests various illegal values for the "modifier" part of an `-l` flag.
+
+fn main() {}
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr b/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr
new file mode 100644
index 00000000000..75950ad9c64
--- /dev/null
+++ b/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr
@@ -0,0 +1,2 @@
+error: unknown linking modifier `ferris`, expected one of: bundle, verbatim, whole-archive, as-needed
+
diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
index 6bc4501b6a3..e8d0be10d4d 100644
--- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr
+++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn smeg() {
    | ^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail
diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs
index 40861e73b39..badb5d4c51d 100644
--- a/tests/ui/never_type/defaulted-never-note.rs
+++ b/tests/ui/never_type/defaulted-never-note.rs
@@ -27,7 +27,7 @@ fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
 //[fallback]~| NOTE required by a bound in `foo`
 fn smeg() {
     //[nofallback]~^ warn: this function depends on never type fallback being `()`
-    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     let _x = return;
     foo(_x);
     //[fallback]~^ ERROR the trait bound
diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.rs b/tests/ui/never_type/dependency-on-fallback-to-unit.rs
index 5448d0be2c6..fad4c7c7df7 100644
--- a/tests/ui/never_type/dependency-on-fallback-to-unit.rs
+++ b/tests/ui/never_type/dependency-on-fallback-to-unit.rs
@@ -7,7 +7,7 @@ fn main() {
 
 fn def() {
     //~^ warn: this function depends on never type fallback being `()`
-    //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     match true {
         false => <_>::default(),
         true => return,
@@ -18,7 +18,7 @@ fn def() {
 // <https://github.com/rust-lang/rust/issues/39216>
 fn question_mark() -> Result<(), ()> {
     //~^ warn: this function depends on never type fallback being `()`
-    //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     deserialize()?;
     Ok(())
 }
diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
index 79f47bb5fbc..2f10428ee93 100644
--- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
+++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn def() {
    | ^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: Default` will fail
@@ -24,7 +24,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn question_mark() -> Result<(), ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: Default` will fail
diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
index d40d1da76f9..35b245bd743 100644
--- a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn assignment() {
    | ^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: UnitDefault` will fail
@@ -24,7 +24,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn assignment_rev() {
    | ^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: UnitDefault` will fail
diff --git a/tests/ui/never_type/diverging-fallback-control-flow.rs b/tests/ui/never_type/diverging-fallback-control-flow.rs
index 575e2e9273c..647667126d4 100644
--- a/tests/ui/never_type/diverging-fallback-control-flow.rs
+++ b/tests/ui/never_type/diverging-fallback-control-flow.rs
@@ -29,7 +29,7 @@ impl UnitDefault for () {
 
 fn assignment() {
     //[nofallback]~^ warn: this function depends on never type fallback being `()`
-    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     let x;
 
     if true {
@@ -41,7 +41,7 @@ fn assignment() {
 
 fn assignment_rev() {
     //[nofallback]~^ warn: this function depends on never type fallback being `()`
-    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     let x;
 
     if true {
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
index d11c21d9573..689791fc460 100644
--- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn main() {
    | ^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: Test` will fail
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs
index c6d59c7f273..75ca491bf46 100644
--- a/tests/ui/never_type/diverging-fallback-no-leak.rs
+++ b/tests/ui/never_type/diverging-fallback-no-leak.rs
@@ -13,7 +13,7 @@ fn unconstrained_arg<T: Test>(_: T) {}
 
 fn main() {
     //[nofallback]~^ warn: this function depends on never type fallback being `()`
-    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
 
     // Here the type variable falls back to `!`,
     // and hence we get a type error.
diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
index 30a5e60a758..42018c54609 100644
--- a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn main() {
    | ^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: UnitReturn` will fail
diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs
index 927991db513..fdea3a94d28 100644
--- a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs
+++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs
@@ -27,7 +27,7 @@ fn unconstrained_return<T: UnitReturn>() -> T {
 
 fn main() {
     //[nofallback]~^ warn: this function depends on never type fallback being `()`
-    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
 
     // In Ye Olde Days, the `T` parameter of `unconstrained_return`
     // winds up "entangled" with the `!` type that results from
diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
index fb0166dd9e0..b5b5d87e7dd 100644
--- a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
+++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn main() {
    | ^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: Bar` will fail
diff --git a/tests/ui/never_type/fallback-closure-ret.rs b/tests/ui/never_type/fallback-closure-ret.rs
index 30f9ac54d0b..f1423354f13 100644
--- a/tests/ui/never_type/fallback-closure-ret.rs
+++ b/tests/ui/never_type/fallback-closure-ret.rs
@@ -20,6 +20,6 @@ fn foo<R: Bar>(_: impl Fn() -> R) {}
 
 fn main() {
     //[nofallback]~^ warn: this function depends on never type fallback being `()`
-    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     foo(|| panic!());
 }
diff --git a/tests/ui/never_type/impl_trait_fallback.rs b/tests/ui/never_type/impl_trait_fallback.rs
index fbe13dbe2ac..bd4caeb2b72 100644
--- a/tests/ui/never_type/impl_trait_fallback.rs
+++ b/tests/ui/never_type/impl_trait_fallback.rs
@@ -7,6 +7,6 @@ impl T for () {}
 
 fn should_ret_unit() -> impl T {
     //~^ warn: this function depends on never type fallback being `()`
-    //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
     panic!()
 }
diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr
index 4496746e018..768c226e989 100644
--- a/tests/ui/never_type/impl_trait_fallback.stderr
+++ b/tests/ui/never_type/impl_trait_fallback.stderr
@@ -4,7 +4,7 @@ warning: this function depends on never type fallback being `()`
 LL | fn should_ret_unit() -> impl T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the types explicitly
 note: in edition 2024, the requirement `!: T` will fail
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
index 6a48a7b9b47..03bb0ca5f3a 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
@@ -4,7 +4,7 @@ warning: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { mem::zeroed() }
    |                  ^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
@@ -19,7 +19,7 @@ warning: never type fallback affects this call to an `unsafe` function
 LL |             core::mem::transmute(Zst)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -33,7 +33,7 @@ warning: never type fallback affects this union access
 LL |         unsafe { Union { a: () }.b }
    |                  ^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
@@ -43,7 +43,7 @@ warning: never type fallback affects this raw pointer dereference
 LL |         unsafe { *ptr::from_ref(&()).cast() }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -57,7 +57,7 @@ warning: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { internally_create(x) }
    |                  ^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -71,7 +71,7 @@ warning: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { zeroed() }
    |                  ^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -85,7 +85,7 @@ warning: never type fallback affects this `unsafe` function
 LL |         let zeroed = mem::zeroed;
    |                      ^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -99,7 +99,7 @@ warning: never type fallback affects this `unsafe` function
 LL |         let f = internally_create;
    |                 ^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -113,7 +113,7 @@ warning: never type fallback affects this call to an `unsafe` method
 LL |             S(marker::PhantomData).create_out_of_thin_air()
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
@@ -126,7 +126,7 @@ LL |             match send_message::<_ /* ?0 */>() {
 LL |         msg_send!();
    |         ----------- in this macro invocation
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
index 844cd62c267..cf12d699f2e 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
@@ -4,7 +4,7 @@ error: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { mem::zeroed() }
    |                  ^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
@@ -19,7 +19,7 @@ error: never type fallback affects this call to an `unsafe` function
 LL |             core::mem::transmute(Zst)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -33,7 +33,7 @@ error: never type fallback affects this union access
 LL |         unsafe { Union { a: () }.b }
    |                  ^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
@@ -43,7 +43,7 @@ error: never type fallback affects this raw pointer dereference
 LL |         unsafe { *ptr::from_ref(&()).cast() }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -57,7 +57,7 @@ error: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { internally_create(x) }
    |                  ^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -71,7 +71,7 @@ error: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { zeroed() }
    |                  ^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -85,7 +85,7 @@ error: never type fallback affects this `unsafe` function
 LL |         let zeroed = mem::zeroed;
    |                      ^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -99,7 +99,7 @@ error: never type fallback affects this `unsafe` function
 LL |         let f = internally_create;
    |                 ^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 help: use `()` annotations to avoid fallback changes
@@ -113,7 +113,7 @@ error: never type fallback affects this call to an `unsafe` method
 LL |             S(marker::PhantomData).create_out_of_thin_air()
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
@@ -126,7 +126,7 @@ LL |             match send_message::<_ /* ?0 */>() {
 LL |         msg_send!();
    |         ----------- in this macro invocation
    |
-   = warning: this will change its meaning in a future release!
+   = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
index c96f4dda3f8..19b51eea2f5 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
@@ -13,7 +13,7 @@ fn _zero() {
         unsafe { mem::zeroed() }
         //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
         //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
         //[e2024]~| warning: the type `!` does not permit zero-initialization
     } else {
         return;
@@ -30,7 +30,7 @@ fn _trans() {
             core::mem::transmute(Zst)
             //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
             //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
-            //~| warn: this will change its meaning in a future release!
+            //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
         }
     } else {
         return;
@@ -47,7 +47,7 @@ fn _union() {
         unsafe { Union { a: () }.b }
         //[e2015]~^ warn: never type fallback affects this union access
         //[e2024]~^^ error: never type fallback affects this union access
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
     } else {
         return;
     };
@@ -58,7 +58,7 @@ fn _deref() {
         unsafe { *ptr::from_ref(&()).cast() }
         //[e2015]~^ warn: never type fallback affects this raw pointer dereference
         //[e2024]~^^ error: never type fallback affects this raw pointer dereference
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
     } else {
         return;
     };
@@ -79,7 +79,7 @@ fn _only_generics() {
         unsafe { internally_create(x) }
         //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
         //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
 
         x.unwrap()
     } else {
@@ -92,12 +92,12 @@ fn _stored_function() {
         let zeroed = mem::zeroed;
         //[e2015]~^ warn: never type fallback affects this `unsafe` function
         //[e2024]~^^ error: never type fallback affects this `unsafe` function
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
 
         unsafe { zeroed() }
         //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
         //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
     } else {
         return;
     };
@@ -115,7 +115,7 @@ fn _only_generics_stored_function() {
         let f = internally_create;
         //[e2015]~^ warn: never type fallback affects this `unsafe` function
         //[e2024]~^^ error: never type fallback affects this `unsafe` function
-        //~| warn: this will change its meaning in a future release!
+        //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
 
         unsafe { f(x) }
 
@@ -140,7 +140,7 @@ fn _method() {
             S(marker::PhantomData).create_out_of_thin_air()
             //[e2015]~^ warn: never type fallback affects this call to an `unsafe` method
             //[e2024]~^^ error: never type fallback affects this call to an `unsafe` method
-            //~| warn: this will change its meaning in a future release!
+            //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
         }
     } else {
         return;
@@ -158,7 +158,7 @@ fn _objc() {
             match send_message::<_ /* ?0 */>() {
                 //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
                 //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
-                //~| warn: this will change its meaning in a future release!
+                //~| warn: this changes meaning in Rust 2024 and in a future release in all editions!
                 Ok(x) => x,
                 Err(_) => loop {},
             }
diff --git a/tests/ui/parser/bad-if-statements.stderr b/tests/ui/parser/bad-if-statements.stderr
index ee839db6455..320b1176993 100644
--- a/tests/ui/parser/bad-if-statements.stderr
+++ b/tests/ui/parser/bad-if-statements.stderr
@@ -29,7 +29,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if true x
    |        ^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if true { x }
    |             +   +
@@ -65,7 +65,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if true x else {}
    |        ^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if true { x } else {}
    |             +   +
diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr
index 83360944ed5..b65de4eac3f 100644
--- a/tests/ui/parser/block-no-opening-brace.stderr
+++ b/tests/ui/parser/block-no-opening-brace.stderr
@@ -6,7 +6,7 @@ LL |     loop
 LL |         let x = 0;
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { let x = 0; }
    |         +            +
@@ -21,7 +21,7 @@ LL |     while true
 LL |         let x = 0;
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { let x = 0; }
    |         +            +
@@ -32,7 +32,7 @@ error: expected `{`, found keyword `let`
 LL |         let x = 0;
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { let x = 0; }
    |         +            +
diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr
index eb8428854af..aacc31ed871 100644
--- a/tests/ui/parser/closure-return-syntax.stderr
+++ b/tests/ui/parser/closure-return-syntax.stderr
@@ -4,7 +4,7 @@ error: expected `{`, found `22`
 LL |     let x = || -> i32 22;
    |                       ^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     let x = || -> i32 { 22 };
    |                       +    +
diff --git a/tests/ui/parser/else-no-if.stderr b/tests/ui/parser/else-no-if.stderr
index 2e3e8f6b50e..eec64b0f4bc 100644
--- a/tests/ui/parser/else-no-if.stderr
+++ b/tests/ui/parser/else-no-if.stderr
@@ -30,7 +30,7 @@ error: expected `{`, found `falsy`
 LL |     } else falsy();
    |            ^^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { falsy() };
    |            +         +
@@ -41,7 +41,7 @@ error: expected `{`, found keyword `loop`
 LL |     } else loop{}
    |            ^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { loop{} }
    |            +        +
@@ -65,7 +65,7 @@ error: expected `{`, found `falsy`
 LL |     } else falsy!();
    |            ^^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { falsy!() };
    |            +          +
@@ -74,12 +74,14 @@ error: expected `{`, found `falsy`
   --> $DIR/else-no-if.rs:47:12
    |
 LL |     } else falsy! {} {
-   |            ^^^^^ expected `{`
+   |       ---- ^^^^^
+   |       |
+   |       expected an `if` or a block after this `else`
    |
-help: try placing this code inside a block
+help: add an `if` if this is the condition of a chained `else if` statement
    |
-LL |     } else { falsy! {} } {
-   |            +           +
+LL |     } else if falsy! {} {
+   |            ++
 
 error: expected `{`, found `falsy`
   --> $DIR/else-no-if.rs:54:12
@@ -87,7 +89,7 @@ error: expected `{`, found `falsy`
 LL |     } else falsy! {};
    |            ^^^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     } else { falsy! {} };
    |            +           +
diff --git a/tests/ui/parser/label-after-block-like.stderr b/tests/ui/parser/label-after-block-like.stderr
index be8c679d8ce..4dea225e3f3 100644
--- a/tests/ui/parser/label-after-block-like.stderr
+++ b/tests/ui/parser/label-after-block-like.stderr
@@ -23,7 +23,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if let () = () 'a {}
    |        ^^^^^^^^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if let () = () { 'a {} }
    |                    +       +
@@ -53,7 +53,7 @@ note: the `if` expression is missing a block after this condition
    |
 LL |     if true 'a {}
    |        ^^^^
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     if true { 'a {} }
    |             +       +
@@ -80,7 +80,7 @@ LL |     loop 'a {}
    |     |
    |     while parsing this `loop` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     loop { 'a {} }
    |          +       +
@@ -108,7 +108,7 @@ LL |     while true 'a {}
    |     |     this `while` condition successfully parsed
    |     while parsing the body of this `while` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     while true { 'a {} }
    |                +       +
@@ -136,7 +136,7 @@ LL |     while let () = () 'a {}
    |     |     this `while` condition successfully parsed
    |     while parsing the body of this `while` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     while let () = () { 'a {} }
    |                       +       +
@@ -161,7 +161,7 @@ error: expected `{`, found `'a`
 LL |     for _ in 0..0 'a {}
    |                   ^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     for _ in 0..0 { 'a {} }
    |                   +       +
@@ -188,7 +188,7 @@ LL |     unsafe 'a {}
    |     |
    |     while parsing this `unsafe` expression
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |     unsafe { 'a {} }
    |            +       +
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed
new file mode 100644
index 00000000000..ea9dc4cf6cc
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.fixed
@@ -0,0 +1,39 @@
+//@ run-rustfix
+#![allow(dead_code)]
+fn main() {
+    for _ in [1, 2, 3].iter().map(|x| x) {}
+    //~^ ERROR expected `{`, found `map`
+    //~| HELP you might have meant to write a method call
+}
+fn foo5() {
+    let x = (vec![1, 2, 3],);
+    for _ in x.0 {}
+    //~^ ERROR expected `{`, found `0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo6() {
+    let x = ((vec![1, 2, 3],),);
+    for _ in x.0.0 {}
+    //~^ ERROR expected `{`, found `0.0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo7() {
+    let x = Some(vec![1, 2, 3]);
+    for _ in x.unwrap() {}
+    //~^ ERROR expected `{`, found `unwrap`
+    //~| HELP you might have meant to write a method call
+}
+fn foo8() {
+    let x = S { a: A { b: vec![1, 2, 3] } };
+    for _ in x.a.b {}
+    //~^ ERROR expected `{`, found `a`
+    //~| HELP you might have meant to write a field access
+}
+
+struct S {
+    a: A,
+}
+
+struct A {
+    b: Vec<i32>,
+}
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs
new file mode 100644
index 00000000000..1833f458a8a
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.rs
@@ -0,0 +1,39 @@
+//@ run-rustfix
+#![allow(dead_code)]
+fn main() {
+    for _ in [1, 2, 3].iter()map(|x| x) {}
+    //~^ ERROR expected `{`, found `map`
+    //~| HELP you might have meant to write a method call
+}
+fn foo5() {
+    let x = (vec![1, 2, 3],);
+    for _ in x 0 {}
+    //~^ ERROR expected `{`, found `0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo6() {
+    let x = ((vec![1, 2, 3],),);
+    for _ in x 0.0 {}
+    //~^ ERROR expected `{`, found `0.0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo7() {
+    let x = Some(vec![1, 2, 3]);
+    for _ in x unwrap() {}
+    //~^ ERROR expected `{`, found `unwrap`
+    //~| HELP you might have meant to write a method call
+}
+fn foo8() {
+    let x = S { a: A { b: vec![1, 2, 3] } };
+    for _ in x a.b {}
+    //~^ ERROR expected `{`, found `a`
+    //~| HELP you might have meant to write a field access
+}
+
+struct S {
+    a: A,
+}
+
+struct A {
+    b: Vec<i32>,
+}
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr
new file mode 100644
index 00000000000..87f76efffa6
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression-fixable.stderr
@@ -0,0 +1,57 @@
+error: expected `{`, found `map`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:4:30
+   |
+LL |     for _ in [1, 2, 3].iter()map(|x| x) {}
+   |                              ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in [1, 2, 3].iter().map(|x| x) {}
+   |                              +
+
+error: expected `{`, found `0`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:10:16
+   |
+LL |     for _ in x 0 {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0 {}
+   |               +
+
+error: expected `{`, found `0.0`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:16:16
+   |
+LL |     for _ in x 0.0 {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0.0 {}
+   |               +
+
+error: expected `{`, found `unwrap`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:22:16
+   |
+LL |     for _ in x unwrap() {}
+   |                ^^^^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in x.unwrap() {}
+   |               +
+
+error: expected `{`, found `a`
+  --> $DIR/missing-dot-on-if-condition-expression-fixable.rs:28:16
+   |
+LL |     for _ in x a.b {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.a.b {}
+   |               +
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs
new file mode 100644
index 00000000000..c4a9ed66a83
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.rs
@@ -0,0 +1,57 @@
+fn main() {
+    for _ in [1, 2, 3].iter()map(|x| x) {}
+    //~^ ERROR expected `{`, found `map`
+    //~| HELP you might have meant to write a method call
+}
+fn foo1() {
+    for _ in 1.3f64 cos() {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a method call
+}
+fn foo2() {
+    for _ in 1.3 cos {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a field access
+}
+fn foo3() {
+    for _ in 1 cos() {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a method call
+}
+fn foo4() {
+    for _ in 1 cos {}
+    //~^ ERROR expected `{`, found `cos`
+    //~| HELP you might have meant to write a field access
+}
+fn foo5() {
+    let x = (vec![1, 2, 3],);
+    for _ in x 0 {}
+    //~^ ERROR expected `{`, found `0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo6() {
+    let x = ((vec![1, 2, 3],),);
+    for _ in x 0.0 {}
+    //~^ ERROR expected `{`, found `0.0`
+    //~| HELP you might have meant to write a field access
+}
+fn foo7() {
+    let x = Some(vec![1, 2, 3]);
+    for _ in x unwrap() {}
+    //~^ ERROR expected `{`, found `unwrap`
+    //~| HELP you might have meant to write a method call
+}
+fn foo8() {
+    let x = S { a: A { b: vec![1, 2, 3] } };
+    for _ in x a.b {}
+    //~^ ERROR expected `{`, found `a`
+    //~| HELP you might have meant to write a field access
+}
+
+struct S {
+    a: A,
+}
+
+struct A {
+    b: Vec<i32>,
+}
diff --git a/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr
new file mode 100644
index 00000000000..bfb72b95682
--- /dev/null
+++ b/tests/ui/parser/recover/missing-dot-on-if-condition-expression.stderr
@@ -0,0 +1,101 @@
+error: expected `{`, found `map`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:2:30
+   |
+LL |     for _ in [1, 2, 3].iter()map(|x| x) {}
+   |                              ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in [1, 2, 3].iter().map(|x| x) {}
+   |                              +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:7:21
+   |
+LL |     for _ in 1.3f64 cos() {}
+   |                     ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in 1.3f64.cos() {}
+   |                    +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:12:18
+   |
+LL |     for _ in 1.3 cos {}
+   |                  ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in 1.3.cos {}
+   |                 +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:17:16
+   |
+LL |     for _ in 1 cos() {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in 1.cos() {}
+   |               +
+
+error: expected `{`, found `cos`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:22:16
+   |
+LL |     for _ in 1 cos {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in 1.cos {}
+   |               +
+
+error: expected `{`, found `0`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:28:16
+   |
+LL |     for _ in x 0 {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0 {}
+   |               +
+
+error: expected `{`, found `0.0`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:34:16
+   |
+LL |     for _ in x 0.0 {}
+   |                ^^^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.0.0 {}
+   |               +
+
+error: expected `{`, found `unwrap`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:40:16
+   |
+LL |     for _ in x unwrap() {}
+   |                ^^^^^^ expected `{`
+   |
+help: you might have meant to write a method call
+   |
+LL |     for _ in x.unwrap() {}
+   |               +
+
+error: expected `{`, found `a`
+  --> $DIR/missing-dot-on-if-condition-expression.rs:46:16
+   |
+LL |     for _ in x a.b {}
+   |                ^ expected `{`
+   |
+help: you might have meant to write a field access
+   |
+LL |     for _ in x.a.b {}
+   |               +
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/parser/suggest-const-for-global-var.stderr b/tests/ui/parser/suggest-const-for-global-var.stderr
index 235e621d882..6ac7fe8f092 100644
--- a/tests/ui/parser/suggest-const-for-global-var.stderr
+++ b/tests/ui/parser/suggest-const-for-global-var.stderr
@@ -2,7 +2,12 @@ error: expected item, found keyword `let`
   --> $DIR/suggest-const-for-global-var.rs:1:1
    |
 LL | let X: i32 = 12;
-   | ^^^ consider using `const` or `static` instead of `let` for global variables
+   | ^^^
+   | |
+   | `let` cannot be used for global variables
+   | help: consider using `static` or `const` instead of `let`
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/suggest-static-for-global-var-mut.rs b/tests/ui/parser/suggest-static-for-global-var-mut.rs
new file mode 100644
index 00000000000..c63b09bb7a7
--- /dev/null
+++ b/tests/ui/parser/suggest-static-for-global-var-mut.rs
@@ -0,0 +1,5 @@
+let mut _data = vec![1,2,3];
+//~^ ERROR expected item, found keyword `let`
+
+fn main() {
+}
diff --git a/tests/ui/parser/suggest-static-for-global-var-mut.stderr b/tests/ui/parser/suggest-static-for-global-var-mut.stderr
new file mode 100644
index 00000000000..4b00d1a24f3
--- /dev/null
+++ b/tests/ui/parser/suggest-static-for-global-var-mut.stderr
@@ -0,0 +1,11 @@
+error: expected item, found keyword `let`
+  --> $DIR/suggest-static-for-global-var-mut.rs:1:1
+   |
+LL | let mut _data = vec![1,2,3];
+   | ^^^ `let` cannot be used for global variables
+   |
+   = help: consider using `static` and a `Mutex` instead of `let mut`
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/unnecessary-let.fixed b/tests/ui/parser/unnecessary-let.fixed
new file mode 100644
index 00000000000..bdee07e76aa
--- /dev/null
+++ b/tests/ui/parser/unnecessary-let.fixed
@@ -0,0 +1,13 @@
+//@ run-rustfix
+
+fn main() {
+    for _x in [1, 2, 3] {}
+    //~^ ERROR expected pattern, found `let`
+    //~| ERROR missing `in` in `for` loop
+
+    match 1 {
+        1 => {}
+        //~^ ERROR expected pattern, found `let`
+        _ => {}
+    }
+}
diff --git a/tests/ui/parser/unnecessary-let.rs b/tests/ui/parser/unnecessary-let.rs
index 6279109621d..a889d9f7789 100644
--- a/tests/ui/parser/unnecessary-let.rs
+++ b/tests/ui/parser/unnecessary-let.rs
@@ -1,5 +1,7 @@
+//@ run-rustfix
+
 fn main() {
-    for let x of [1, 2, 3] {}
+    for let _x of [1, 2, 3] {}
     //~^ ERROR expected pattern, found `let`
     //~| ERROR missing `in` in `for` loop
 
diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr
index 05ac1faafd4..0b28123747a 100644
--- a/tests/ui/parser/unnecessary-let.stderr
+++ b/tests/ui/parser/unnecessary-let.stderr
@@ -1,31 +1,31 @@
 error: expected pattern, found `let`
-  --> $DIR/unnecessary-let.rs:2:9
+  --> $DIR/unnecessary-let.rs:4:9
    |
-LL |     for let x of [1, 2, 3] {}
-   |         ^^^^
+LL |     for let _x of [1, 2, 3] {}
+   |         ^^^
    |
 help: remove the unnecessary `let` keyword
    |
-LL -     for let x of [1, 2, 3] {}
-LL +     for x of [1, 2, 3] {}
+LL -     for let _x of [1, 2, 3] {}
+LL +     for _x of [1, 2, 3] {}
    |
 
 error: missing `in` in `for` loop
-  --> $DIR/unnecessary-let.rs:2:15
+  --> $DIR/unnecessary-let.rs:4:16
    |
-LL |     for let x of [1, 2, 3] {}
-   |               ^^
+LL |     for let _x of [1, 2, 3] {}
+   |                ^^
    |
 help: try using `in` here instead
    |
-LL |     for let x in [1, 2, 3] {}
-   |               ~~
+LL |     for let _x in [1, 2, 3] {}
+   |                ~~
 
 error: expected pattern, found `let`
-  --> $DIR/unnecessary-let.rs:7:9
+  --> $DIR/unnecessary-let.rs:9:9
    |
 LL |         let 1 => {}
-   |         ^^^^
+   |         ^^^
    |
 help: remove the unnecessary `let` keyword
    |
diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs
index 0b3e7ce9e9a..16737e0a894 100644
--- a/tests/ui/pattern/usefulness/conflicting_bindings.rs
+++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs
@@ -10,6 +10,8 @@ fn main() {
     //~^ ERROR: mutable more than once
     if let Some(ref mut y @ ref mut z) = x && true {}
     //~^ ERROR: mutable more than once
+    if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {}
+    //~^ ERROR: mutable more than once
     while let Some(ref mut y @ ref mut z) = x {}
     //~^ ERROR: mutable more than once
     while let Some(ref mut y @ ref mut z) = x && true {}
diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr
index 679fc83e7f5..6f6504e6f64 100644
--- a/tests/ui/pattern/usefulness/conflicting_bindings.stderr
+++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr
@@ -31,7 +31,15 @@ LL |     if let Some(ref mut y @ ref mut z) = x && true {}
    |                 value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:13:20
+  --> $DIR/conflicting_bindings.rs:13:43
+   |
+LL |     if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {}
+   |                                           ^^^^^^^^^   --------- value is mutably borrowed by `z` here
+   |                                           |
+   |                                           value is mutably borrowed by `y` here
+
+error: cannot borrow value as mutable more than once at a time
+  --> $DIR/conflicting_bindings.rs:15:20
    |
 LL |     while let Some(ref mut y @ ref mut z) = x {}
    |                    ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -39,7 +47,7 @@ LL |     while let Some(ref mut y @ ref mut z) = x {}
    |                    value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:15:20
+  --> $DIR/conflicting_bindings.rs:17:20
    |
 LL |     while let Some(ref mut y @ ref mut z) = x && true {}
    |                    ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -47,7 +55,7 @@ LL |     while let Some(ref mut y @ ref mut z) = x && true {}
    |                    value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:18:9
+  --> $DIR/conflicting_bindings.rs:20:9
    |
 LL |         ref mut y @ ref mut z => {}
    |         ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -55,12 +63,12 @@ LL |         ref mut y @ ref mut z => {}
    |         value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:21:24
+  --> $DIR/conflicting_bindings.rs:23:24
    |
 LL |         () if let Some(ref mut y @ ref mut z) = x => {}
    |                        ^^^^^^^^^   --------- value is mutably borrowed by `z` here
    |                        |
    |                        value is mutably borrowed by `y` here
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
index e4dd35a5995..60b4fcca286 100644
--- a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
+++ b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
@@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
    |
 LL |     match (true, false) {
    |           ^^^^^^^^^^^^^ pattern `(true, false)` not covered
+LL |
+LL |         TRUE_TRUE => (),
+   |         --------- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `TRUE_TRUE`
    |
    = note: the matched value is of type `(bool, bool)`
+note: constant `TRUE_TRUE` defined here
+  --> $DIR/match-arm-statics-2.rs:14:1
+   |
+LL | const TRUE_TRUE: (bool, bool) = (true, true);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         TRUE_TRUE_var => (),
+   |                  ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         (false, true) => (),
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
index a8786d02414..0a3991fe3d1 100644
--- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -199,8 +199,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         CONST => {},
@@ -212,8 +224,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         &[false] => {},
@@ -225,8 +249,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         CONST => {},
@@ -238,8 +274,20 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         CONST => {},
@@ -251,8 +299,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
    |
 LL |     match s {
    |           ^ pattern `&[false]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &[_, _, ..] => {},
@@ -264,8 +324,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
    |
 LL |     match s1 {
    |           ^^ pattern `&[false]` not covered
+LL |
+LL |         CONST1 => {}
+   |         ------ this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST1`
    |
    = note: the matched value is of type `&[bool; 1]`
+note: constant `CONST1` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:124:5
+   |
+LL |     const CONST1: &[bool; 1] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST1_var => {}
+   |               ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         CONST1 => {},
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
index 5c333cd7795..47653efffb7 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
@@ -94,4 +94,15 @@ fn use_in_arm_ok(c: bool) {
     };
 }
 
+fn use_in_same_chain(c: bool) {
+    let x: Box<_> = Box::new(1);
+
+    let v = (1, 2);
+
+    match v {
+        (1, 2) if let y = x && c && let z = x => false, //~ ERROR use of moved value: `x`
+        _ => true,
+    };
+}
+
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr
index 087e54244b3..123c5f19430 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr
@@ -60,6 +60,22 @@ help: borrow this binding in the pattern to avoid moving the value
 LL |         (1, 2) if let ref y = x && c => false,
    |                       +++
 
-error: aborting due to 4 previous errors
+error[E0382]: use of moved value: `x`
+  --> $DIR/move-guard-if-let-chain.rs:103:41
+   |
+LL |     let x: Box<_> = Box::new(1);
+   |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+...
+LL |         (1, 2) if let y = x && c && let z = x => false,
+   |                       -                 ^ value used here after move
+   |                       |
+   |                       value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         (1, 2) if let ref y = x && c && let z = x => false,
+   |                       +++
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
new file mode 100644
index 00000000000..389c76337f0
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
@@ -0,0 +1,25 @@
+// issue-103476
+//@ compile-flags: -Zlint-mir -Zunstable-options
+//@ edition: 2024
+//@ check-pass
+
+#![feature(let_chains)]
+#![allow(irrefutable_let_patterns)]
+
+struct Pd;
+
+impl Pd {
+    fn it(&self) -> It {
+        todo!()
+    }
+}
+
+pub struct It<'a>(Box<dyn Tr<'a>>);
+
+trait Tr<'a> {}
+
+fn f(m: Option<Pd>) {
+    if let Some(n) = m && let it = n.it() {};
+}
+
+fn main() {}
diff --git a/tests/ui/simd-abi-checks-s390x.rs b/tests/ui/simd-abi-checks-s390x.rs
new file mode 100644
index 00000000000..15df66a2ced
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.rs
@@ -0,0 +1,174 @@
+//@ revisions: z10 z13_no_vector z13_soft_float
+//@ build-fail
+//@[z10] compile-flags: --target s390x-unknown-linux-gnu
+//@[z10] needs-llvm-components: systemz
+//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector
+//@[z13_no_vector] needs-llvm-components: systemz
+// FIXME: +soft-float itself doesn't set -vector
+//@[z13_soft_float] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector,+soft-float
+//@[z13_soft_float] needs-llvm-components: systemz
+
+#![feature(no_core, lang_items, repr_simd, s390x_target_feature)]
+#![no_core]
+#![crate_type = "lib"]
+#![allow(non_camel_case_types, improper_ctypes_definitions)]
+#![deny(abi_unsupported_vector_types)]
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "freeze"]
+pub trait Freeze {}
+
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
+#[repr(simd)]
+pub struct i8x8([i8; 8]);
+#[repr(simd)]
+pub struct i8x16([i8; 16]);
+#[repr(simd)]
+pub struct i8x32([i8; 32]);
+#[repr(C)]
+pub struct Wrapper<T>(T);
+#[repr(transparent)]
+pub struct TransparentWrapper<T>(T);
+
+impl Copy for i8 {}
+impl Copy for i64 {}
+impl Copy for i8x8 {}
+impl Copy for i8x16 {}
+impl Copy for i8x32 {}
+impl<T: Copy> Copy for Wrapper<T> {}
+impl<T: Copy> Copy for TransparentWrapper<T> {}
+
+#[no_mangle]
+extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+#[target_feature(enable = "vector")]
+unsafe extern "C" fn vector_ret_target_feature_small(x: &i8x8) -> i8x8 {
+    // Ok
+    *x
+}
+#[no_mangle]
+#[target_feature(enable = "vector")]
+unsafe extern "C" fn vector_target_feature_ret(x: &i8x16) -> i8x16 {
+    // Ok
+    *x
+}
+#[no_mangle]
+#[target_feature(enable = "vector")]
+unsafe extern "C" fn vector_ret_target_feature_large(x: &i8x32) -> i8x32 {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> {
+    // Ok
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> {
+    // Ok
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_ret_small(
+    x: &TransparentWrapper<i8x8>,
+) -> TransparentWrapper<i8x8> {
+    //~^^^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_ret(
+    x: &TransparentWrapper<i8x16>,
+) -> TransparentWrapper<i8x16> {
+    //~^^^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_ret_large(
+    x: &TransparentWrapper<i8x32>,
+) -> TransparentWrapper<i8x32> {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const i8x8 as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_arg(x: i8x16) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const i8x16 as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_arg_large(x: i8x32) -> i64 {
+    // Ok
+    unsafe { *(&x as *const i8x32 as *const i64) }
+}
+
+#[no_mangle]
+extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const Wrapper<i8x8> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const Wrapper<i8x16> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 {
+    // Ok
+    unsafe { *(&x as *const Wrapper<i8x32> as *const i64) }
+}
+
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 {
+    // Ok
+    unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) }
+}
diff --git a/tests/ui/simd-abi-checks-s390x.z10.stderr b/tests/ui/simd-abi-checks-s390x.z10.stderr
new file mode 100644
index 00000000000..a91322ec058
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.z10.stderr
@@ -0,0 +1,111 @@
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:46:1
+   |
+LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+note: the lint level is defined here
+  --> $DIR/simd-abi-checks-s390x.rs:15:9
+   |
+LL | #![deny(abi_unsupported_vector_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:52:1
+   |
+LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:99:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret_small(
+LL | |     x: &TransparentWrapper<i8x8>,
+LL | | ) -> TransparentWrapper<i8x8> {
+   | |_____________________________^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:107:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret(
+LL | |     x: &TransparentWrapper<i8x16>,
+LL | | ) -> TransparentWrapper<i8x16> {
+   | |______________________________^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:123:1
+   |
+LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:129:1
+   |
+LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:141:1
+   |
+LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:147:1
+   |
+LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:159:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:165:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
new file mode 100644
index 00000000000..a91322ec058
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
@@ -0,0 +1,111 @@
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:46:1
+   |
+LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+note: the lint level is defined here
+  --> $DIR/simd-abi-checks-s390x.rs:15:9
+   |
+LL | #![deny(abi_unsupported_vector_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:52:1
+   |
+LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:99:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret_small(
+LL | |     x: &TransparentWrapper<i8x8>,
+LL | | ) -> TransparentWrapper<i8x8> {
+   | |_____________________________^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:107:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret(
+LL | |     x: &TransparentWrapper<i8x16>,
+LL | | ) -> TransparentWrapper<i8x16> {
+   | |______________________________^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:123:1
+   |
+LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:129:1
+   |
+LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:141:1
+   |
+LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:147:1
+   |
+LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:159:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:165:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
new file mode 100644
index 00000000000..a91322ec058
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
@@ -0,0 +1,111 @@
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:46:1
+   |
+LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+note: the lint level is defined here
+  --> $DIR/simd-abi-checks-s390x.rs:15:9
+   |
+LL | #![deny(abi_unsupported_vector_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:52:1
+   |
+LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:99:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret_small(
+LL | |     x: &TransparentWrapper<i8x8>,
+LL | | ) -> TransparentWrapper<i8x8> {
+   | |_____________________________^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:107:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret(
+LL | |     x: &TransparentWrapper<i8x16>,
+LL | | ) -> TransparentWrapper<i8x16> {
+   | |______________________________^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:123:1
+   |
+LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:129:1
+   |
+LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:141:1
+   |
+LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:147:1
+   |
+LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:159:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:165:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/stats/hir-stats.rs b/tests/ui/stats/input-stats.rs
index 7c5da8cf554..f19a53cc610 100644
--- a/tests/ui/stats/hir-stats.rs
+++ b/tests/ui/stats/input-stats.rs
@@ -1,6 +1,6 @@
 //@ check-pass
-//@ compile-flags: -Zhir-stats
-//@ only-x86_64
+//@ compile-flags: -Zinput-stats
+//@ only-64bit
 // layout randomization affects the hir stat output
 //@ needs-deterministic-layouts
 
@@ -11,7 +11,7 @@
 
 
 // The aim here is to include at least one of every different type of top-level
-// AST/HIR node reported by `-Zhir-stats`.
+// AST/HIR node reported by `-Zinput-stats`.
 
 #![allow(dead_code)]
 
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/input-stats.stderr
index bd0c8cbc3b1..2cc2c8019fa 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -53,7 +53,7 @@ ast-stats-1 - Enum                     136 ( 2.0%)             1
 ast-stats-1 - Fn                       272 ( 4.1%)             2
 ast-stats-1 - Use                      408 ( 6.1%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  6_640
+ast-stats-1 Total                  6_640                   116
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -113,7 +113,7 @@ ast-stats-2 - ForeignMod               136 ( 1.9%)             1
 ast-stats-2 - Fn                       272 ( 3.7%)             2
 ast-stats-2 - Use                      544 ( 7.5%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  7_288
+ast-stats-2 Total                  7_288                   127
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
@@ -174,5 +174,5 @@ hir-stats - Use                      352 ( 3.9%)             4
 hir-stats Path                   1_240 (13.7%)            31            40
 hir-stats PathSegment            1_920 (21.3%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  9_024
+hir-stats Total                  9_024                   180
 hir-stats
diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs
index 0183bdba111..a3b510848dc 100644
--- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs
+++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs
@@ -1,8 +1,6 @@
-//@ ignore-apple: cycle error does not appear on apple
+use std::cell::UnsafeCell;
 
-use std::sync::Mutex;
-
-enum Foo { X(Mutex<Option<Foo>>) }
+enum Foo { X(UnsafeCell<Option<Foo>>) }
 //~^ ERROR recursive type `Foo` has infinite size
 //~| ERROR cycle detected
 
diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr
index 22f8519d0ef..b192593d266 100644
--- a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr
+++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr
@@ -1,18 +1,18 @@
 error[E0072]: recursive type `Foo` has infinite size
-  --> $DIR/issue-17431-6.rs:5:1
+  --> $DIR/issue-17431-6.rs:3:1
    |
-LL | enum Foo { X(Mutex<Option<Foo>>) }
-   | ^^^^^^^^                  --- recursive without indirection
+LL | enum Foo { X(UnsafeCell<Option<Foo>>) }
+   | ^^^^^^^^                       --- recursive without indirection
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
    |
-LL | enum Foo { X(Mutex<Option<Box<Foo>>>) }
-   |                           ++++   +
+LL | enum Foo { X(UnsafeCell<Option<Box<Foo>>>) }
+   |                                ++++   +
 
 error[E0391]: cycle detected when computing when `Foo` needs drop
-  --> $DIR/issue-17431-6.rs:5:1
+  --> $DIR/issue-17431-6.rs:3:1
    |
-LL | enum Foo { X(Mutex<Option<Foo>>) }
+LL | enum Foo { X(UnsafeCell<Option<Foo>>) }
    | ^^^^^^^^
    |
    = note: ...which immediately requires computing when `Foo` needs drop again
diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 05e087fd9f9..a040e71cf3b 100644
--- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -31,6 +31,10 @@ note: required by a bound in `bar`
    |
 LL | fn bar(f: impl Future<Output=()>) {}
    |                ^^^^^^^^^^^^^^^^^ required by this bound in `bar`
+help: use parentheses to call this closure
+   |
+LL |     bar(async_closure());
+   |                      ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
index af47ba8baa3..1a440a90cd7 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
@@ -2,9 +2,9 @@ fn main() {
     let A = 3;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-    //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     //~| SUGGESTION A_var
 
     const A: i32 = 2;
+    //~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
 }
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index b6c28612802..a275d8e4e83 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -2,15 +2,18 @@ error[E0005]: refutable pattern in local binding
   --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
    |
 LL |     let A = 3;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `A_var`
+   |         ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
+...
+LL |     const A: i32 = 2;
+   |     ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let A_var = 3;
+   |         ~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/symbol-names/basic.rs b/tests/ui/symbol-names/basic.rs
index dfcac21ccd6..839dda2b3a3 100644
--- a/tests/ui/symbol-names/basic.rs
+++ b/tests/ui/symbol-names/basic.rs
@@ -1,7 +1,7 @@
 //@ build-fail
 //@ revisions: legacy v0
 //@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
-    //@[v0]compile-flags: -C symbol-mangling-version=v0
+//@[v0]compile-flags: -C symbol-mangling-version=v0
 
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/symbol-names/impl1.rs b/tests/ui/symbol-names/impl1.rs
index fa4be88f68f..9aefca47447 100644
--- a/tests/ui/symbol-names/impl1.rs
+++ b/tests/ui/symbol-names/impl1.rs
@@ -1,7 +1,7 @@
 //@ build-fail
 //@ revisions: legacy v0
 //@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
-    //@[v0]compile-flags: -C symbol-mangling-version=v0
+//@[v0]compile-flags: -C symbol-mangling-version=v0
 //@[legacy]normalize-stderr-test: "h[\w]{16}E?\)" -> "<SYMBOL_HASH>)"
 
 #![feature(auto_traits, rustc_attrs)]
diff --git a/tests/ui/symbol-names/issue-60925.rs b/tests/ui/symbol-names/issue-60925.rs
index 9f1f007a0fa..ca0f21b7a78 100644
--- a/tests/ui/symbol-names/issue-60925.rs
+++ b/tests/ui/symbol-names/issue-60925.rs
@@ -1,7 +1,7 @@
 //@ build-fail
 //@ revisions: legacy v0
 //@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
-    //@[v0]compile-flags: -C symbol-mangling-version=v0
+//@[v0]compile-flags: -C symbol-mangling-version=v0
 
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout
index 1840be7885b..5588cfdfa5c 100644
--- a/tests/ui/thir-print/thir-flat-const-variant.stdout
+++ b/tests/ui/thir-print/thir-flat-const-variant.stdout
@@ -11,9 +11,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0),
         },
         Expr {
@@ -25,9 +28,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0),
         },
         Expr {
@@ -47,9 +53,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0),
         },
         Expr {
@@ -61,9 +70,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0),
         },
     ],
@@ -84,9 +96,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0),
         },
         Expr {
@@ -98,9 +113,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0),
         },
         Expr {
@@ -120,9 +138,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0),
         },
         Expr {
@@ -134,9 +155,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0),
         },
     ],
@@ -157,9 +181,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0),
         },
         Expr {
@@ -171,9 +198,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0),
         },
         Expr {
@@ -193,9 +223,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0),
         },
         Expr {
@@ -207,9 +240,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0),
         },
     ],
@@ -230,9 +266,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0),
         },
         Expr {
@@ -244,9 +283,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0),
         },
         Expr {
@@ -266,9 +308,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0),
         },
         Expr {
@@ -280,9 +325,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0),
         },
     ],
@@ -312,9 +360,12 @@ Thir {
                 block: b0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0),
         },
         Expr {
@@ -326,9 +377,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0),
         },
     ],
diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout
index a31d08adab6..59cecfe511c 100644
--- a/tests/ui/thir-print/thir-flat.stdout
+++ b/tests/ui/thir-print/thir-flat.stdout
@@ -20,9 +20,12 @@ Thir {
                 block: b0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
         },
         Expr {
@@ -34,9 +37,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
         },
     ],
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 8cff7887661..a9d6985928a 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -26,7 +26,7 @@ params: [
 body:
     Expr {
         ty: bool
-        temp_lifetime: Some(Node(26))
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
         kind: 
             Scope {
@@ -35,7 +35,7 @@ body:
                 value:
                     Expr {
                         ty: bool
-                        temp_lifetime: Some(Node(26))
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
                         kind: 
                             Block {
@@ -47,7 +47,7 @@ body:
                                 expr:
                                     Expr {
                                         ty: bool
-                                        temp_lifetime: Some(Node(26))
+                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                         kind: 
                                             Scope {
@@ -56,14 +56,14 @@ body:
                                                 value:
                                                     Expr {
                                                         ty: bool
-                                                        temp_lifetime: Some(Node(26))
+                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                                         kind: 
                                                             Match {
                                                                 scrutinee:
                                                                     Expr {
                                                                         ty: Foo
-                                                                        temp_lifetime: Some(Node(26))
+                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                         kind: 
                                                                             Scope {
@@ -72,7 +72,7 @@ body:
                                                                                 value:
                                                                                     Expr {
                                                                                         ty: Foo
-                                                                                        temp_lifetime: Some(Node(26))
+                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
                                                                                             VarRef {
@@ -123,7 +123,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(13))
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -132,7 +132,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -175,7 +175,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(19))
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -184,7 +184,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -219,7 +219,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(24))
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -228,7 +228,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@@ -257,7 +257,7 @@ params: [
 body:
     Expr {
         ty: ()
-        temp_lifetime: Some(Node(2))
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
         span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
         kind: 
             Scope {
@@ -266,7 +266,7 @@ body:
                 value:
                     Expr {
                         ty: ()
-                        temp_lifetime: Some(Node(2))
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
                         span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
                         kind: 
                             Block {
diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout
index ef6db368dbe..b39581ad841 100644
--- a/tests/ui/thir-print/thir-tree.stdout
+++ b/tests/ui/thir-print/thir-tree.stdout
@@ -4,7 +4,7 @@ params: [
 body:
     Expr {
         ty: ()
-        temp_lifetime: Some(Node(2))
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
         span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
         kind: 
             Scope {
@@ -13,7 +13,7 @@ body:
                 value:
                     Expr {
                         ty: ()
-                        temp_lifetime: Some(Node(2))
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
                         span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
                         kind: 
                             Block {
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 2cb63f25d06..fd0e9691700 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
@@ -1,7 +1,7 @@
 trait Trait {}
 
 fn test<T: ?self::<i32>::Trait>() {}
-//~^ ERROR type arguments are not allowed on this type
+//~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args`
 //~| WARN relaxing a default bound only does something for `?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 701e493f5a5..0c167fff940 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
@@ -4,13 +4,13 @@ warning: relaxing a default bound only does something for `?Sized`; all other tr
 LL | fn test<T: ?self::<i32>::Trait>() {}
    |            ^^^^^^^^^^^^^^^^^^^
 
-error[E0109]: type arguments are not allowed on this type
+error[E0109]: type arguments are not allowed on module `maybe_bound_has_path_args`
   --> $DIR/maybe-bound-has-path-args.rs:3:20
    |
 LL | fn test<T: ?self::<i32>::Trait>() {}
    |             ----   ^^^ type argument not allowed
    |             |
-   |             not allowed on this type
+   |             not allowed on module `maybe_bound_has_path_args`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 25c81ff900f..0970cd5225f 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -12,5 +12,13 @@ LL | const fn test() -> impl ~const Fn() {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 2 previous errors
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-parse-not-item.rs:7:25
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
deleted file mode 100644
index c26eaf67454..00000000000
--- a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-//@ known-bug: #110395
-//@ failure-status: 101
-//@ dont-check-compiler-stderr
-// FIXME(const_trait_impl) check-pass
-//@ compile-flags: -Znext-solver
-
-#![crate_type = "lib"]
-#![allow(internal_features, incomplete_features)]
-#![no_std]
-#![no_core]
-#![feature(
-    auto_traits,
-    const_trait_impl,
-    effects,
-    lang_items,
-    no_core,
-    staged_api,
-    unboxed_closures,
-    rustc_attrs,
-    marker_trait_attr,
-)]
-#![stable(feature = "minicore", since = "1.0.0")]
-
-fn test() {
-    fn is_const_fn<F>(_: F)
-    where
-        F: const FnOnce<()>,
-    {
-    }
-
-    const fn foo() {}
-
-    is_const_fn(foo);
-}
-
-/// ---------------------------------------------------------------------- ///
-/// Const fn trait definitions
-
-#[const_trait]
-#[lang = "fn"]
-#[rustc_paren_sugar]
-trait Fn<Args: Tuple>: ~const FnMut<Args> {
-    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
-}
-
-#[const_trait]
-#[lang = "fn_mut"]
-#[rustc_paren_sugar]
-trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-}
-
-#[const_trait]
-#[lang = "fn_once"]
-#[rustc_paren_sugar]
-trait FnOnce<Args: Tuple> {
-    #[lang = "fn_once_output"]
-    type Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-/// ---------------------------------------------------------------------- ///
-/// All this other stuff needed for core. Unrelated to test.
-
-#[lang = "destruct"]
-#[const_trait]
-trait Destruct {}
-
-#[lang = "freeze"]
-unsafe auto trait Freeze {}
-
-#[lang = "drop"]
-#[const_trait]
-trait Drop {
-    fn drop(&mut self);
-}
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-#[lang = "tuple_trait"]
-trait Tuple {}
-
-#[lang = "legacy_receiver"]
-trait LegacyReceiver {}
-
-impl<T: ?Sized> LegacyReceiver for &T {}
diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr
new file mode 100644
index 00000000000..e43a6b603fd
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-opaque.no.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): const Foo` is not satisfied
+  --> $DIR/const-opaque.rs:31:18
+   |
+LL |     let opaque = bar(());
+   |                  ^^^^^^^
+
+error[E0277]: the trait bound `(): const Foo` is not satisfied
+  --> $DIR/const-opaque.rs:33:5
+   |
+LL |     opaque.method();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/const-opaque.rs b/tests/ui/traits/const-traits/const-opaque.rs
new file mode 100644
index 00000000000..96cdd7d9f26
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-opaque.rs
@@ -0,0 +1,38 @@
+//@ revisions: yes no
+//@ compile-flags: -Znext-solver
+//@[yes] check-pass
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Foo {
+    fn method(&self);
+}
+
+impl<T: ~const Foo> const Foo for (T,) {
+    fn method(&self) {}
+}
+
+#[cfg(yes)]
+impl const Foo for () {
+    fn method(&self) {}
+}
+
+#[cfg(no)]
+impl Foo for () {
+    fn method(&self) {}
+}
+
+const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo {
+    (t,)
+}
+
+const _: () = {
+    let opaque = bar(());
+    //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied
+    opaque.method();
+    //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied
+    std::mem::forget(opaque);
+};
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
index c467088ab3d..8ff15dd09cc 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
@@ -3,6 +3,7 @@
 const fn test() -> impl ~const Fn() {
     //~^ 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_trait]` traits
     const move || { //~ ERROR const closures are experimental
         let sl: &[u8] = b"foo";
 
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index 6d7edaf19f2..879d966b1f9 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -1,5 +1,5 @@
 error[E0658]: const closures are experimental
-  --> $DIR/ice-112822-expected-type-for-param.rs:6:5
+  --> $DIR/ice-112822-expected-type-for-param.rs:7:5
    |
 LL |     const move || {
    |     ^^^^^
@@ -22,8 +22,16 @@ LL | const fn test() -> impl ~const Fn() {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/ice-112822-expected-type-for-param.rs:3:25
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+  --> $DIR/ice-112822-expected-type-for-param.rs:12:17
    |
 LL |                 assert_eq!(first, &b'f');
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +40,7 @@ LL |                 assert_eq!(first, &b'f');
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions
-  --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+  --> $DIR/ice-112822-expected-type-for-param.rs:12:17
    |
 LL |                 assert_eq!(first, &b'f');
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +48,7 @@ LL |                 assert_eq!(first, &b'f');
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0015, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs
new file mode 100644
index 00000000000..ee47f92a0bc
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs
@@ -0,0 +1,22 @@
+//@ aux-build:minicore.rs
+//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort
+//@ check-pass
+
+#![feature(no_core, const_trait_impl)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+fn is_const_fn<F>(_: F)
+where
+    F: const FnOnce(),
+{
+}
+
+const fn foo() {}
+
+fn test() {
+    is_const_fn(foo);
+}
diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs
new file mode 100644
index 00000000000..ae1cbc6ca58
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs
@@ -0,0 +1,21 @@
+//@ aux-build:minicore.rs
+//@ compile-flags: --crate-type=lib -Znext-solver
+
+#![feature(no_core, const_trait_impl)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
+
+#[const_trait]
+trait Foo {}
+impl Foo for () {}
+const fn foo<T: ~const Foo>() {}
+
+const fn test() {
+    call_indirect(&foo::<()>);
+    //~^ ERROR the trait bound `(): ~const Foo` is not satisfied
+}
diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr
new file mode 100644
index 00000000000..cf158643b34
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): ~const Foo` is not satisfied
+  --> $DIR/minicore-fn-fail.rs:19:5
+   |
+LL |     call_indirect(&foo::<()>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/effects/minicore-works.rs b/tests/ui/traits/const-traits/effects/minicore-works.rs
index bfbfa8b2d05..c79b4fc07df 100644
--- a/tests/ui/traits/const-traits/effects/minicore-works.rs
+++ b/tests/ui/traits/const-traits/effects/minicore-works.rs
@@ -20,3 +20,9 @@ const fn test_op() {
     let _x = Add::add(1, 2);
     let _y = Custom + Custom;
 }
+
+const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
+
+const fn call() {
+    call_indirect(&call);
+}
diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.rs b/tests/ui/traits/negative-bounds/on-unimplemented.rs
index 34582590861..5f2a705ed56 100644
--- a/tests/ui/traits/negative-bounds/on-unimplemented.rs
+++ b/tests/ui/traits/negative-bounds/on-unimplemented.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.diagnostic.on_unimplemented.intro
+
 #![feature(negative_bounds)]
 
 #[diagnostic::on_unimplemented(message = "this ain't fooing")]
diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.stderr b/tests/ui/traits/negative-bounds/on-unimplemented.stderr
index ed473d57917..8a295611010 100644
--- a/tests/ui/traits/negative-bounds/on-unimplemented.stderr
+++ b/tests/ui/traits/negative-bounds/on-unimplemented.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `NotFoo: !Foo` is not satisfied
-  --> $DIR/on-unimplemented.rs:7:15
+  --> $DIR/on-unimplemented.rs:9:15
    |
 LL | fn hello() -> impl !Foo {
    |               ^^^^^^^^^ the trait bound `NotFoo: !Foo` is not satisfied
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
index dda42580e0f..2a301788525 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
@@ -7,6 +7,7 @@ fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
     //~^ ERROR associated type `Assoc` not found for `Trait`
     //~| ERROR associated type `Assoc` not found for `Trait`
     //~| the trait bound `{integer}: Trait<()>` is not satisfied
+    //~| ERROR cannot capture late-bound type parameter in nested `impl Trait`
     16
 }
 
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
index 6e5bd34ce38..38dcdbd0af2 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
@@ -1,3 +1,9 @@
+error: cannot capture late-bound type parameter in nested `impl Trait`
+  --> $DIR/non-lifetime-binder-in-constraint.rs:6:58
+   |
+LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
+   |                          - parameter defined here        ^
+
 error[E0220]: associated type `Assoc` not found for `Trait`
   --> $DIR/non-lifetime-binder-in-constraint.rs:6:39
    |
@@ -27,7 +33,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Trait<T: ?Sized> {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0220, E0277.
 For more information about an error, try `rustc --explain E0220`.
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs
index 23951c34270..23f3666618b 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs
@@ -5,6 +5,7 @@ trait Trait<T> {}
 
 fn f() -> impl for<T> Trait<impl Trait<T>> {}
 //~^ ERROR nested `impl Trait` is not allowed
-//~| ERROR the trait bound `(): Trait<impl Trait<T>>` is not satisfied
+//~| ERROR the trait bound `(): Trait<impl Trait<{type error}>>` is not satisfied
+//~| ERROR cannot capture late-bound type parameter in nested `impl Trait`
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr
index 5859d952b75..3c352c9889c 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr
@@ -7,11 +7,19 @@ LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
    |           |                 nested `impl Trait` here
    |           outer `impl Trait`
 
-error[E0277]: the trait bound `(): Trait<impl Trait<T>>` is not satisfied
+error: cannot capture late-bound type parameter in nested `impl Trait`
+  --> $DIR/non-lifetime-binder.rs:6:40
+   |
+LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
+   |                    -                   ^
+   |                    |
+   |                    parameter defined here
+
+error[E0277]: the trait bound `(): Trait<impl Trait<{type error}>>` is not satisfied
   --> $DIR/non-lifetime-binder.rs:6:11
    |
 LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<T>>` is not implemented for `()`
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<{type error}>>` is not implemented for `()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/non-lifetime-binder.rs:4:1
@@ -19,7 +27,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Trait<T> {}
    | ^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0666.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/unsafe/unsafe-block-without-braces.stderr b/tests/ui/unsafe/unsafe-block-without-braces.stderr
index d29e49d73a6..3d8234c15e7 100644
--- a/tests/ui/unsafe/unsafe-block-without-braces.stderr
+++ b/tests/ui/unsafe/unsafe-block-without-braces.stderr
@@ -6,7 +6,7 @@ LL |     unsafe //{
 LL |         std::mem::transmute::<f32, u32>(1.0);
    |         ^^^ expected `{`
    |
-help: try placing this code inside a block
+help: you might have meant to write this as part of a block
    |
 LL |         { std::mem::transmute::<f32, u32>(1.0); }
    |         +                                       +
diff --git a/triagebot.toml b/triagebot.toml
index d5bc549ca9f..2483bfc4a41 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -236,7 +236,21 @@ trigger_files = [
     "compiler",
 
     # Tests
+    "tests/assembly",
+    "tests/auxiliary",
+    "tests/codegen",
+    "tests/codegen-units",
+    "tests/COMPILER_TESTS.md",
+    "tests/coverage",
+    "tests/coverage-run-rustdoc",
+    "tests/crashes",
+    "tests/debuginfo",
+    "tests/incremental",
+    "tests/mir-opt",
+    "tests/pretty",
+    "tests/run-make",
     "tests/ui",
+    "tests/ui-fulldeps",
 ]
 exclude_labels = [
     "T-*",
@@ -353,21 +367,22 @@ trigger_files = [
 
 [autolabel."T-bootstrap"]
 trigger_files = [
-    "x.py",
-    "x",
-    "x.ps1",
+    "Cargo.toml",
+    "configure",
+    "config.example.toml",
     "src/bootstrap",
+    "src/build_helper",
     "src/tools/rust-installer",
     "src/tools/x",
-    "configure",
-    "Cargo.toml",
-    "config.example.toml",
     "src/stage0",
     "src/tools/compiletest",
     "src/tools/tidy",
     "src/tools/rustdoc-gui-test",
     "src/tools/libcxx-version",
     "src/tools/rustc-perf-wrapper",
+    "x.py",
+    "x",
+    "x.ps1"
 ]
 
 [autolabel."T-infra"]
@@ -886,7 +901,7 @@ message = "This PR changes a file inside `tests/crashes`. If a crash was fixed,
 message = "Changes to the code generated for builtin derived traits."
 cc = ["@nnethercote"]
 
-[mentions."tests/ui/stats/hir-stats.stderr"]
+[mentions."tests/ui/stats/input-stats.stderr"]
 message = "Changes to the size of AST and/or HIR nodes."
 cc = ["@nnethercote"]
 
@@ -997,7 +1012,6 @@ compiler = [
     "@oli-obk",
     "@petrochenkov",
     "@pnkfelix",
-    "@TaKO8Ki",
     "@wesleywiser",
 ]
 libs = [
@@ -1048,7 +1062,6 @@ diagnostics = [
     "@davidtwco",
     "@estebank",
     "@oli-obk",
-    "@TaKO8Ki",
     "@chenyukang",
 ]
 parser = [